aboutsummaryrefslogtreecommitdiff
path: root/packages/sdk/src/in-memory-store.ts
blob: 5f839aae369a9f46143430ede23e424895aa392d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { randomUUID } from "node:crypto";
import type { MemoryNotFoundError, MemoryStore } from "./memory-store.js";
import { failure, type Result, success } from "./result.js";
import type {
	Memory,
	MemoryCreateInput,
	MemoryFilter,
	MemoryUpdateInput,
} from "./types.js";

function generateId(): string {
	return randomUUID();
}

function memoryNotFoundError(memoryId: string): MemoryNotFoundError {
	return { type: "MEMORY_NOT_FOUND", memoryId };
}

function matchesFilter(memory: Memory, filter: MemoryFilter): boolean {
	if (filter.projectId && memory.projectId !== filter.projectId) {
		return false;
	}

	if (filter.folderId && memory.folderId !== filter.folderId) {
		return false;
	}

	if (filter.tags && filter.tags.length > 0) {
		const memoryTagIds = new Set(memory.tags.map((tag) => tag.id));
		const hasAllTags = filter.tags.every((tagId) => memoryTagIds.has(tagId));

		if (!hasAllTags) {
			return false;
		}
	}

	return true;
}

export class InMemoryStore implements MemoryStore {
	private memories: Map<string, Memory> = new Map();

	async create(input: MemoryCreateInput): Promise<Memory> {
		const now = new Date();
		const memory: Memory = {
			id: generateId(),
			content: input.content,
			projectId: input.projectId,
			folderId: input.folderId ?? null,
			tags: input.tags ?? [],
			metadata: input.metadata ?? {},
			createdAt: now,
			updatedAt: now,
		};

		this.memories.set(memory.id, memory);

		return memory;
	}

	async read(id: string): Promise<Result<Memory, MemoryNotFoundError>> {
		const memory = this.memories.get(id);

		if (!memory) {
			return failure(memoryNotFoundError(id));
		}

		return success(memory);
	}

	async update(
		id: string,
		input: MemoryUpdateInput,
	): Promise<Result<Memory, MemoryNotFoundError>> {
		const existing = this.memories.get(id);

		if (!existing) {
			return failure(memoryNotFoundError(id));
		}

		const updated: Memory = {
			...existing,
			content: input.content ?? existing.content,
			projectId:
				input.projectId !== undefined ? input.projectId : existing.projectId,
			folderId:
				input.folderId !== undefined ? input.folderId : existing.folderId,
			tags: input.tags ?? existing.tags,
			metadata: input.metadata ?? existing.metadata,
			updatedAt: new Date(),
		};

		this.memories.set(id, updated);

		return success(updated);
	}

	async delete(id: string): Promise<Result<void, MemoryNotFoundError>> {
		if (!this.memories.has(id)) {
			return failure(memoryNotFoundError(id));
		}

		this.memories.delete(id);

		return success(undefined);
	}

	async list(filter?: MemoryFilter): Promise<Memory[]> {
		const allMemories = Array.from(this.memories.values());

		if (!filter) {
			return allMemories;
		}

		return allMemories.filter((memory) => matchesFilter(memory, filter));
	}
}