mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
Enforce strict Effect tsgo migrations
This commit is contained in:
parent
64fb23e7d0
commit
f6878d4dd7
49 changed files with 5547 additions and 3250 deletions
|
|
@ -66,7 +66,7 @@ export function makeTriplesStoreService(config: ProcessorConfig): TriplesStoreSe
|
|||
),
|
||||
),
|
||||
});
|
||||
console.log("[TriplesStore] Service initialized");
|
||||
void Effect.runPromise(Effect.log("[TriplesStore] Service initialized"));
|
||||
return service;
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +78,6 @@ export const program = makeFlowProcessorProgram<ProcessorConfig & FalkorDBConfig
|
|||
layer: (config) => FalkorDBTriplesStoreLive(config),
|
||||
});
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
await Effect.runPromise(program);
|
||||
export function run(): Promise<void> {
|
||||
return Effect.runPromise(program);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* FalkorDB triples store — writes RDF triples to a FalkorDB graph.
|
||||
* FalkorDB triples store - writes RDF triples to a FalkorDB graph.
|
||||
*
|
||||
* FalkorDB is Redis-based and uses Cypher queries, same as the Python impl.
|
||||
* Pairs well with Graphiti which also uses FalkorDB as its backend.
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import { createClient, Graph } from "falkordb";
|
||||
import { errorMessage, type Term, type Triple } from "@trustgraph/base";
|
||||
import { Context, Effect, Layer } from "effect";
|
||||
import { Config, Context, Effect, Layer } from "effect";
|
||||
import * as S from "effect/Schema";
|
||||
|
||||
export interface FalkorDBConfig {
|
||||
|
|
@ -26,7 +26,7 @@ function getTermValue(term: Term): string {
|
|||
case "BLANK":
|
||||
return term.id;
|
||||
case "TRIPLE":
|
||||
return getTermValue(term.triple.s); // fallback
|
||||
return getTermValue(term.triple.s);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,113 +55,6 @@ export interface FalkorDBTriplesStore {
|
|||
readonly deleteCollection: (user: string, collection: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export function makeFalkorDBTriplesStore(config: FalkorDBConfig = {}): FalkorDBTriplesStore {
|
||||
const url = config.url ?? process.env.FALKORDB_URL ?? "redis://localhost:6379";
|
||||
const database = config.database ?? "falkordb";
|
||||
|
||||
const client = createClient({ url });
|
||||
const graph = new Graph(client, database);
|
||||
const connectPromise = client.connect().then(() => {
|
||||
console.log(`[FalkorDBTriplesStore] Connected to ${url}, graph: ${database}`);
|
||||
}).catch((err) => {
|
||||
console.error(`[FalkorDBTriplesStore] Connection failed:`, err);
|
||||
throw err;
|
||||
});
|
||||
|
||||
const ensureConnected = async (): Promise<void> => {
|
||||
await connectPromise;
|
||||
};
|
||||
|
||||
const createNode = async (uri: string, user: string, collection: string): Promise<void> => {
|
||||
await ensureConnected();
|
||||
await graph.query(
|
||||
"MERGE (n:Node {uri: $uri, user: $user, collection: $collection})",
|
||||
{ params: { uri, user, collection } },
|
||||
);
|
||||
};
|
||||
|
||||
const createLiteral = async (value: string, user: string, collection: string): Promise<void> => {
|
||||
await ensureConnected();
|
||||
await graph.query(
|
||||
"MERGE (n:Literal {value: $value, user: $user, collection: $collection})",
|
||||
{ params: { value, user, collection } },
|
||||
);
|
||||
};
|
||||
|
||||
const relateNode = async (
|
||||
src: string, uri: string, dest: string,
|
||||
user: string, collection: string,
|
||||
): Promise<void> => {
|
||||
await ensureConnected();
|
||||
await graph.query(
|
||||
"MATCH (src:Node {uri: $src, user: $user, collection: $collection}) " +
|
||||
"MATCH (dest:Node {uri: $dest, user: $user, collection: $collection}) " +
|
||||
"MERGE (src)-[:Rel {uri: $uri, user: $user, collection: $collection}]->(dest)",
|
||||
{ params: { src, dest, uri, user, collection } },
|
||||
);
|
||||
};
|
||||
|
||||
const relateLiteral = async (
|
||||
src: string, uri: string, dest: string,
|
||||
user: string, collection: string,
|
||||
): Promise<void> => {
|
||||
await ensureConnected();
|
||||
await graph.query(
|
||||
"MATCH (src:Node {uri: $src, user: $user, collection: $collection}) " +
|
||||
"MATCH (dest:Literal {value: $dest, user: $user, collection: $collection}) " +
|
||||
"MERGE (src)-[:Rel {uri: $uri, user: $user, collection: $collection}]->(dest)",
|
||||
{ params: { src, dest, uri, user, collection } },
|
||||
);
|
||||
};
|
||||
|
||||
const storeTriples = async (
|
||||
triples: Triple[],
|
||||
user = "default",
|
||||
collection = "default",
|
||||
): Promise<void> => {
|
||||
for (const t of triples) {
|
||||
const s = getTermValue(t.s);
|
||||
const p = getTermValue(t.p);
|
||||
const o = getTermValue(t.o);
|
||||
|
||||
await createNode(s, user, collection);
|
||||
|
||||
if (t.o.type === "IRI") {
|
||||
await createNode(o, user, collection);
|
||||
await relateNode(s, p, o, user, collection);
|
||||
} else {
|
||||
await createLiteral(o, user, collection);
|
||||
await relateLiteral(s, p, o, user, collection);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteCollection = async (user: string, collection: string): Promise<void> => {
|
||||
await ensureConnected();
|
||||
await graph.query(
|
||||
"MATCH (n:Node {user: $user, collection: $collection}) DETACH DELETE n",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
await graph.query(
|
||||
"MATCH (n:Literal {user: $user, collection: $collection}) DETACH DELETE n",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
await graph.query(
|
||||
"MATCH (c:CollectionMetadata {user: $user, collection: $collection}) DELETE c",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
createNode,
|
||||
createLiteral,
|
||||
relateNode,
|
||||
relateLiteral,
|
||||
storeTriples,
|
||||
deleteCollection,
|
||||
};
|
||||
}
|
||||
|
||||
export class FalkorDBTriplesStoreError extends S.TaggedErrorClass<FalkorDBTriplesStoreError>()(
|
||||
"FalkorDBTriplesStoreError",
|
||||
{
|
||||
|
|
@ -190,35 +83,268 @@ export class FalkorDBTriplesStoreService extends Context.Service<
|
|||
"@trustgraph/flow/storage/triples/falkordb/FalkorDBTriplesStoreService",
|
||||
) {}
|
||||
|
||||
const falkorDBTriplesStoreError = (operation: string, cause: unknown) =>
|
||||
new FalkorDBTriplesStoreError({
|
||||
const falkorDBTriplesStoreError = (operation: string, cause: unknown): FalkorDBTriplesStoreError =>
|
||||
FalkorDBTriplesStoreError.make({
|
||||
operation,
|
||||
message: errorMessage(cause),
|
||||
cause,
|
||||
});
|
||||
|
||||
interface FalkorDBStoreConnection {
|
||||
readonly graph: Graph;
|
||||
}
|
||||
|
||||
type FalkorDBQueryOptions = Parameters<Graph["query"]>[1];
|
||||
|
||||
interface FalkorDBTriplesStoreEffectShape {
|
||||
readonly createNode: (
|
||||
uri: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
readonly createLiteral: (
|
||||
value: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
readonly relateNode: (
|
||||
src: string,
|
||||
uri: string,
|
||||
dest: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
readonly relateLiteral: (
|
||||
src: string,
|
||||
uri: string,
|
||||
dest: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
readonly storeTriples: (
|
||||
triples: ReadonlyArray<Triple>,
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
readonly deleteCollection: (
|
||||
user: string,
|
||||
collection: string,
|
||||
) => Effect.Effect<void, FalkorDBTriplesStoreError>;
|
||||
}
|
||||
|
||||
const resolveFalkorDBStoreConfig = Effect.fn("FalkorDBTriplesStore.resolveConfig")(function* (
|
||||
config: FalkorDBConfig,
|
||||
) {
|
||||
const url = config.url ?? (yield* Config.string("FALKORDB_URL").pipe(
|
||||
Config.withDefault("redis://localhost:6379"),
|
||||
Effect.mapError((cause) => falkorDBTriplesStoreError("config", cause)),
|
||||
));
|
||||
return {
|
||||
url,
|
||||
database: config.database ?? "falkordb",
|
||||
};
|
||||
});
|
||||
|
||||
const connectFalkorDBTriplesStore = (
|
||||
config: FalkorDBConfig,
|
||||
): Effect.Effect<FalkorDBStoreConnection, FalkorDBTriplesStoreError> =>
|
||||
Effect.gen(function* () {
|
||||
const { url, database } = yield* resolveFalkorDBStoreConfig(config);
|
||||
const { client, graph } = yield* Effect.try({
|
||||
try: () => {
|
||||
const client = createClient({ url });
|
||||
return { client, graph: new Graph(client, database) };
|
||||
},
|
||||
catch: (cause) => falkorDBTriplesStoreError("create-client", cause),
|
||||
});
|
||||
|
||||
yield* Effect.tryPromise({
|
||||
try: () => client.connect(),
|
||||
catch: (cause) => falkorDBTriplesStoreError("connect", cause),
|
||||
}).pipe(
|
||||
Effect.tapError((error) =>
|
||||
Effect.logError("[FalkorDBTriplesStore] Connection failed", {
|
||||
error: error.message,
|
||||
operation: error.operation,
|
||||
})
|
||||
),
|
||||
);
|
||||
|
||||
yield* Effect.log(`[FalkorDBTriplesStore] Connected to ${url}, graph: ${database}`);
|
||||
return { graph };
|
||||
});
|
||||
|
||||
const runGraphQuery = (
|
||||
graph: Graph,
|
||||
operation: string,
|
||||
query: string,
|
||||
options?: FalkorDBQueryOptions,
|
||||
): Effect.Effect<void, FalkorDBTriplesStoreError> =>
|
||||
Effect.tryPromise({
|
||||
try: () => graph.query(query, options),
|
||||
catch: (cause) => falkorDBTriplesStoreError(operation, cause),
|
||||
}).pipe(
|
||||
Effect.asVoid,
|
||||
);
|
||||
|
||||
const makeFalkorDBTriplesStoreEffect = (
|
||||
config: FalkorDBConfig = {},
|
||||
): FalkorDBTriplesStoreEffectShape => {
|
||||
let cachedConnection: Effect.Effect<FalkorDBStoreConnection, FalkorDBTriplesStoreError> | undefined;
|
||||
|
||||
const getConnection = Effect.fn("FalkorDBTriplesStore.connection")(function* () {
|
||||
if (cachedConnection === undefined) {
|
||||
cachedConnection = yield* Effect.cached(connectFalkorDBTriplesStore(config));
|
||||
}
|
||||
return yield* cachedConnection;
|
||||
});
|
||||
|
||||
const createNode = Effect.fn("FalkorDBTriplesStore.createNode")(function* (
|
||||
uri: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
const { graph } = yield* getConnection();
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"create-node",
|
||||
"MERGE (n:Node {uri: $uri, user: $user, collection: $collection})",
|
||||
{ params: { uri, user, collection } },
|
||||
);
|
||||
});
|
||||
|
||||
const createLiteral = Effect.fn("FalkorDBTriplesStore.createLiteral")(function* (
|
||||
value: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
const { graph } = yield* getConnection();
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"create-literal",
|
||||
"MERGE (n:Literal {value: $value, user: $user, collection: $collection})",
|
||||
{ params: { value, user, collection } },
|
||||
);
|
||||
});
|
||||
|
||||
const relateNode = Effect.fn("FalkorDBTriplesStore.relateNode")(function* (
|
||||
src: string,
|
||||
uri: string,
|
||||
dest: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
const { graph } = yield* getConnection();
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"relate-node",
|
||||
"MATCH (src:Node {uri: $src, user: $user, collection: $collection}) " +
|
||||
"MATCH (dest:Node {uri: $dest, user: $user, collection: $collection}) " +
|
||||
"MERGE (src)-[:Rel {uri: $uri, user: $user, collection: $collection}]->(dest)",
|
||||
{ params: { src, dest, uri, user, collection } },
|
||||
);
|
||||
});
|
||||
|
||||
const relateLiteral = Effect.fn("FalkorDBTriplesStore.relateLiteral")(function* (
|
||||
src: string,
|
||||
uri: string,
|
||||
dest: string,
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
const { graph } = yield* getConnection();
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"relate-literal",
|
||||
"MATCH (src:Node {uri: $src, user: $user, collection: $collection}) " +
|
||||
"MATCH (dest:Literal {value: $dest, user: $user, collection: $collection}) " +
|
||||
"MERGE (src)-[:Rel {uri: $uri, user: $user, collection: $collection}]->(dest)",
|
||||
{ params: { src, dest, uri, user, collection } },
|
||||
);
|
||||
});
|
||||
|
||||
const storeTriples = Effect.fn("FalkorDBTriplesStore.storeTriples")(function* (
|
||||
triples: ReadonlyArray<Triple>,
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
for (const triple of triples) {
|
||||
const s = getTermValue(triple.s);
|
||||
const p = getTermValue(triple.p);
|
||||
const o = getTermValue(triple.o);
|
||||
|
||||
yield* createNode(s, user, collection);
|
||||
|
||||
if (triple.o.type === "IRI") {
|
||||
yield* createNode(o, user, collection);
|
||||
yield* relateNode(s, p, o, user, collection);
|
||||
} else {
|
||||
yield* createLiteral(o, user, collection);
|
||||
yield* relateLiteral(s, p, o, user, collection);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const deleteCollection = Effect.fn("FalkorDBTriplesStore.deleteCollection")(function* (
|
||||
user: string,
|
||||
collection: string,
|
||||
) {
|
||||
const { graph } = yield* getConnection();
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"delete-collection-nodes",
|
||||
"MATCH (n:Node {user: $user, collection: $collection}) DETACH DELETE n",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"delete-collection-literals",
|
||||
"MATCH (n:Literal {user: $user, collection: $collection}) DETACH DELETE n",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
yield* runGraphQuery(
|
||||
graph,
|
||||
"delete-collection-metadata",
|
||||
"MATCH (c:CollectionMetadata {user: $user, collection: $collection}) DELETE c",
|
||||
{ params: { user, collection } },
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
createNode,
|
||||
createLiteral,
|
||||
relateNode,
|
||||
relateLiteral,
|
||||
storeTriples,
|
||||
deleteCollection,
|
||||
};
|
||||
};
|
||||
|
||||
export function makeFalkorDBTriplesStore(config: FalkorDBConfig = {}): FalkorDBTriplesStore {
|
||||
const store = makeFalkorDBTriplesStoreEffect(config);
|
||||
return {
|
||||
createNode: (uri, user, collection) =>
|
||||
Effect.runPromise(store.createNode(uri, user, collection)),
|
||||
createLiteral: (value, user, collection) =>
|
||||
Effect.runPromise(store.createLiteral(value, user, collection)),
|
||||
relateNode: (src, uri, dest, user, collection) =>
|
||||
Effect.runPromise(store.relateNode(src, uri, dest, user, collection)),
|
||||
relateLiteral: (src, uri, dest, user, collection) =>
|
||||
Effect.runPromise(store.relateLiteral(src, uri, dest, user, collection)),
|
||||
storeTriples: (triples, user = "default", collection = "default") =>
|
||||
Effect.runPromise(store.storeTriples(triples, user, collection)),
|
||||
deleteCollection: (user, collection) =>
|
||||
Effect.runPromise(store.deleteCollection(user, collection)),
|
||||
};
|
||||
}
|
||||
|
||||
export const makeFalkorDBTriplesStoreService = (
|
||||
config: FalkorDBConfig = {},
|
||||
): FalkorDBTriplesStoreServiceShape => {
|
||||
const store = makeFalkorDBTriplesStore(config);
|
||||
const store = makeFalkorDBTriplesStoreEffect(config);
|
||||
return {
|
||||
storeTriples: Effect.fn("FalkorDBTriplesStore.storeTriples")((
|
||||
triples: ReadonlyArray<Triple>,
|
||||
user: string,
|
||||
collection: string,
|
||||
) =>
|
||||
Effect.tryPromise({
|
||||
try: () => store.storeTriples(Array.from(triples), user, collection),
|
||||
catch: (cause) => falkorDBTriplesStoreError("store-triples", cause),
|
||||
})),
|
||||
deleteCollection: Effect.fn("FalkorDBTriplesStore.deleteCollection")((
|
||||
user: string,
|
||||
collection: string,
|
||||
) =>
|
||||
Effect.tryPromise({
|
||||
try: () => store.deleteCollection(user, collection),
|
||||
catch: (cause) => falkorDBTriplesStoreError("delete-collection", cause),
|
||||
})),
|
||||
storeTriples: store.storeTriples,
|
||||
deleteCollection: store.deleteCollection,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue