abstract application-to-database interface
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
export interface Entity<T, ID> {
|
||||
construct: (data: T) => T;
|
||||
create: (data: T) => Promise<T>;
|
||||
createMany: (data: T[]) => Promise<T[]>;
|
||||
findAll: () => Promise<T[]>;
|
||||
findById: (id: ID) => Promise<T | undefined>;
|
||||
update: (id: ID, data: Partial<T>) => Promise<void>;
|
||||
delete: (id: ID) => Promise<void>;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Low } from "lowdb";
|
||||
import { JSONFile } from "lowdb/node";
|
||||
import type { CommittedMessage } from "../types";
|
||||
import type { Entity } from "./common";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
export type Conversation = {
|
||||
id: string;
|
||||
@@ -51,3 +53,209 @@ export const db = new Low<DB>(new JSONFile("db.json"), {
|
||||
await db.read();
|
||||
/** Write the database to the file, in case it didn't exist before. */
|
||||
await db.write();
|
||||
|
||||
const conversations: Entity<Conversation, string> & {
|
||||
fetchMessages: (conversationId: string) => Promise<Array<CommittedMessage>>;
|
||||
} = {
|
||||
construct: (conversation: Conversation) => conversation,
|
||||
create: async (conversation: Conversation) => {
|
||||
conversation.id = conversation.id ?? nanoid();
|
||||
await db.data.conversations.push(conversation);
|
||||
await db.write();
|
||||
return conversation;
|
||||
},
|
||||
createMany: async (conversations: Array<Conversation>) => {
|
||||
await db.data.conversations.push(...conversations);
|
||||
await db.write();
|
||||
return conversations;
|
||||
},
|
||||
findAll: async () => {
|
||||
return db.data.conversations;
|
||||
},
|
||||
findById: async (id) => {
|
||||
return db.data.conversations.find((c) => c.id === id);
|
||||
},
|
||||
update: async (id, data: Partial<Conversation>) => {
|
||||
const conversationIndex = db.data.conversations.findIndex(
|
||||
(c) => c.id === id
|
||||
);
|
||||
if (conversationIndex === -1) throw new Error("Conversation not found");
|
||||
db.data.conversations[conversationIndex] = {
|
||||
...db.data.conversations[conversationIndex],
|
||||
...data,
|
||||
};
|
||||
await db.write();
|
||||
},
|
||||
delete: async (id) => {
|
||||
db.data.conversations.splice(
|
||||
db.data.conversations.findIndex((c) => c.id === id),
|
||||
1
|
||||
);
|
||||
const deletedMessageIds = db.data.messages
|
||||
.filter((m) => m.conversationId === id)
|
||||
.map((m) => m.id);
|
||||
db.data.messages = db.data.messages.filter((m) => m.conversationId !== id);
|
||||
const deletedFactIds = db.data.facts
|
||||
.filter((fact) => deletedMessageIds.includes(fact.sourceMessageId))
|
||||
.map((fact) => fact.id);
|
||||
db.data.facts = db.data.facts.filter(
|
||||
(fact) => !deletedFactIds.includes(fact.id)
|
||||
);
|
||||
db.data.factTriggers = db.data.factTriggers.filter(
|
||||
(factTrigger) => !deletedFactIds.includes(factTrigger.sourceFactId)
|
||||
);
|
||||
await db.write();
|
||||
},
|
||||
fetchMessages: async (conversationId) => {
|
||||
const rows = await db.data.messages.filter(
|
||||
(m) => m.conversationId === conversationId
|
||||
);
|
||||
return rows as Array<CommittedMessage>;
|
||||
},
|
||||
};
|
||||
|
||||
const factTriggers: Entity<FactTrigger, string> & {
|
||||
findByFactId: (factId: string) => Promise<Array<FactTrigger>>;
|
||||
} = {
|
||||
construct: (factTrigger: FactTrigger) => factTrigger,
|
||||
create: async (factTrigger: FactTrigger) => {
|
||||
factTrigger.id = factTrigger.id ?? nanoid();
|
||||
await db.data.factTriggers.push(factTrigger);
|
||||
await db.write();
|
||||
return factTrigger;
|
||||
},
|
||||
createMany: async (factTriggers: Array<FactTrigger>) => {
|
||||
await db.data.factTriggers.push(...factTriggers);
|
||||
await db.write();
|
||||
return factTriggers;
|
||||
},
|
||||
findAll: async () => {
|
||||
return db.data.factTriggers;
|
||||
},
|
||||
findById: async (id) => {
|
||||
return db.data.factTriggers.find((factTrigger) => factTrigger.id === id);
|
||||
},
|
||||
update: async (id, data: Partial<FactTrigger>) => {
|
||||
const factTriggerIndex = db.data.factTriggers.findIndex(
|
||||
(factTrigger) => factTrigger.id === id
|
||||
);
|
||||
if (factTriggerIndex === -1) throw new Error("Fact trigger not found");
|
||||
db.data.factTriggers[factTriggerIndex] = {
|
||||
...db.data.factTriggers[factTriggerIndex],
|
||||
...data,
|
||||
};
|
||||
await db.write();
|
||||
},
|
||||
delete: async (id) => {
|
||||
const deletedFactTriggerIndex = db.data.factTriggers.findIndex(
|
||||
(factTrigger) => factTrigger.id === id
|
||||
);
|
||||
if (deletedFactTriggerIndex === -1)
|
||||
throw new Error("Fact trigger not found");
|
||||
db.data.factTriggers.splice(deletedFactTriggerIndex, 1);
|
||||
await db.write();
|
||||
},
|
||||
findByFactId: async (factId: string) => {
|
||||
return db.data.factTriggers.filter(
|
||||
(factTrigger) => factTrigger.sourceFactId === factId
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const facts: Entity<Fact, string> & {
|
||||
findByConversationId: (conversationId: string) => Promise<Array<Fact>>;
|
||||
} = {
|
||||
construct: (fact: Fact) => fact,
|
||||
create: async (fact: Fact) => {
|
||||
fact.id = fact.id ?? nanoid();
|
||||
await db.data.facts.push(fact);
|
||||
await db.write();
|
||||
return fact;
|
||||
},
|
||||
createMany: async (facts: Array<Fact>) => {
|
||||
await db.data.facts.push(...facts);
|
||||
await db.write();
|
||||
return facts;
|
||||
},
|
||||
findAll: async () => {
|
||||
return db.data.facts;
|
||||
},
|
||||
findById: async (id) => {
|
||||
return db.data.facts.find((fact) => fact.id === id);
|
||||
},
|
||||
update: async (id, data: Partial<Fact>) => {
|
||||
const factIndex = db.data.facts.findIndex((fact) => fact.id === id);
|
||||
if (factIndex === -1) throw new Error("Fact not found");
|
||||
db.data.facts[factIndex] = {
|
||||
...db.data.facts[factIndex],
|
||||
...data,
|
||||
};
|
||||
await db.write();
|
||||
},
|
||||
delete: async (id) => {
|
||||
const deletedFactId = db.data.facts.findIndex((fact) => fact.id === id);
|
||||
if (deletedFactId === -1) throw new Error("Fact not found");
|
||||
db.data.facts.splice(deletedFactId, 1);
|
||||
await db.write();
|
||||
},
|
||||
findByConversationId: async (conversationId) => {
|
||||
const conversationMessageIds = db.data.messages
|
||||
.filter((m) => m.conversationId === conversationId)
|
||||
.map((m) => m.id);
|
||||
const rows = await db.data.facts.filter((f) =>
|
||||
conversationMessageIds.includes(f.sourceMessageId)
|
||||
);
|
||||
return rows as Array<Fact>;
|
||||
},
|
||||
};
|
||||
|
||||
const messages: Entity<CommittedMessage, string> & {
|
||||
findByConversationId: (
|
||||
conversationId: string
|
||||
) => Promise<Array<CommittedMessage>>;
|
||||
} = {
|
||||
construct: (message: CommittedMessage) => message,
|
||||
create: async (message: CommittedMessage) => {
|
||||
message.id = message.id ?? nanoid();
|
||||
await db.data.messages.push(message);
|
||||
await db.write();
|
||||
return message;
|
||||
},
|
||||
createMany: async (messages: Array<CommittedMessage>) => {
|
||||
await db.data.messages.push(...messages);
|
||||
await db.write();
|
||||
return messages;
|
||||
},
|
||||
findAll: async () => {
|
||||
return db.data.messages;
|
||||
},
|
||||
findById: async (id) => {
|
||||
return db.data.messages.find((m) => m.id === id);
|
||||
},
|
||||
update: async (id, data: Partial<CommittedMessage>) => {
|
||||
const messageIndex = db.data.messages.findIndex((m) => m.id === id);
|
||||
if (messageIndex === -1) throw new Error("Message not found");
|
||||
db.data.messages[messageIndex] = {
|
||||
...db.data.messages[messageIndex],
|
||||
...data,
|
||||
};
|
||||
await db.write();
|
||||
},
|
||||
delete: async (id) => {
|
||||
db.data.messages.splice(
|
||||
db.data.messages.findIndex((m) => m.id === id),
|
||||
1
|
||||
);
|
||||
await db.write();
|
||||
},
|
||||
findByConversationId: async (conversationId) => {
|
||||
return db.data.messages.filter((m) => m.conversationId === conversationId);
|
||||
},
|
||||
};
|
||||
|
||||
export const _db = {
|
||||
conversations,
|
||||
factTriggers,
|
||||
facts,
|
||||
messages,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user