Skip to main content

dbmemory

  • addKnowledge - Adds a key-value pair to the in-memory database.
  • getKnowledge - Retrieves a value from the in-memory database by key.

Quick Start Guide

The dbmemory module provides a fast in-memory key-value store for caching and temporary data storage. It supports all JavaScript data types and is ideal for:

  • Session Management: Store user sessions and preferences
  • Caching: Cache frequently accessed data for performance
  • State Management: Maintain application state across operations
  • Temporary Data: Store intermediate processing results

Basic Usage

import codebolt from '@codebolt/codeboltjs';

// Store data
await codebolt.dbmemory.addKnowledge('user:123', {
name: 'John Doe',
email: 'john@example.com',
role: 'developer'
});

// Retrieve data
const user = await codebolt.dbmemory.getKnowledge('user:123');
console.log('User:', user.value);

// Update data (simply add again with same key)
await codebolt.dbmemory.addKnowledge('user:123', {
...user.value,
lastLogin: new Date().toISOString()
});

Common Workflows

Workflow 1: User Session Cache

class SessionCache {
async createUserSession(userId, userData) {
const sessionId = `session:${userId}:${Date.now()}`;

const sessionData = {
userId,
userData,
createdAt: new Date().toISOString(),
lastAccessed: new Date().toISOString(),
expiresAt: new Date(Date.now() + 3600000).toISOString() // 1 hour
};

await codebolt.dbmemory.addKnowledge(sessionId, sessionData);
await codebolt.dbmemory.addKnowledge(`user:${userId}:active_session`, sessionId);

return sessionId;
}

async getSession(sessionId) {
const result = await codebolt.dbmemory.getKnowledge(sessionId);

if (!result.value) {
return null;
}

// Check if expired
const session = result.value;
if (new Date(session.expiresAt) < new Date()) {
await this.deleteSession(sessionId);
return null;
}

// Update last accessed
session.lastAccessed = new Date().toISOString();
await codebolt.dbmemory.addKnowledge(sessionId, session);

return session;
}

async deleteSession(sessionId) {
const session = await this.getSession(sessionId);
if (session) {
await codebolt.dbmemory.addKnowledge(`user:${session.userId}:active_session`, null);
await codebolt.dbmemory.addKnowledge(sessionId, null);
}
}
}

// Usage
const cache = new SessionCache();
const sessionId = await cache.createUserSession('user_123', { name: 'John' });
const session = await cache.getSession(sessionId);

Workflow 2: API Response Cache

class ApiCache {
constructor(ttl = 300000) { // 5 minutes default
this.ttl = ttl;
}

async get(key, fetchFn) {
// Try to get from cache
const cached = await codebolt.dbmemory.getKnowledge(`cache:${key}`);

if (cached.value && cached.value.data) {
// Check if still valid
if (Date.now() - cached.value.timestamp < this.ttl) {
console.log('Cache hit:', key);
return cached.value.data;
}
}

// Cache miss or expired, fetch new data
console.log('Cache miss:', key);
const data = await fetchFn();

// Store in cache
await codebolt.dbmemory.addKnowledge(`cache:${key}`, {
data,
timestamp: Date.now()
});

return data;
}

async invalidate(key) {
await codebolt.dbmemory.addKnowledge(`cache:${key}`, null);
}

async clear() {
// Clear all cache entries (requires knowing keys)
await codebolt.dbmemory.addKnowledge('cache:cleared_at', Date.now());
}
}

// Usage
const apiCache = new ApiCache(60000); // 1 minute TTL

const users = await apiCache.get('users', async () => {
// Expensive API call
return await fetchUsersFromAPI();
});

// Next call returns cached data
const cachedUsers = await apiCache.get('users', async () => {
return await fetchUsersFromAPI();
});

Workflow 3: Rate Limiting

class RateLimiter {
async checkLimit(identifier, limit, windowMs) {
const key = `ratelimit:${identifier}`;
const now = Date.now();
const windowStart = now - windowMs;

// Get current requests
const result = await codebolt.dbmemory.getKnowledge(key);
const requests = result.value || [];

// Filter out old requests
const validRequests = requests.filter(time => time > windowStart);

// Check if limit exceeded
if (validRequests.length >= limit) {
return {
allowed: false,
remaining: 0,
resetAt: validRequests[0] + windowMs
};
}

// Add current request
validRequests.push(now);
await codebolt.dbmemory.addKnowledge(key, validRequests);

return {
allowed: true,
remaining: limit - validRequests.length,
resetAt: now + windowMs
};
}
}

// Usage
const rateLimiter = new RateLimiter();

// Check rate limit for API calls
const result = await rateLimiter.checkLimit('api:user_123', 100, 60000);

if (!result.allowed) {
console.log('Rate limit exceeded. Try again in:', result.resetAt);
} else {
console.log('Request allowed. Remaining:', result.remaining);
}

Workflow 4: Data Aggregation

class DataAggregator {
async addDataPoint(metric, value) {
const key = `aggregate:${metric}`;
const result = await codebolt.dbmemory.getKnowledge(key);

const data = result.value || {
count: 0,
sum: 0,
min: Infinity,
max: -Infinity,
values: []
};

// Update statistics
data.count++;
data.sum += value;
data.min = Math.min(data.min, value);
data.max = Math.max(data.max, value);
data.values.push({ value, timestamp: Date.now() });

// Keep only last 1000 values
if (data.values.length > 1000) {
data.values.shift();
}

await codebolt.dbmemory.addKnowledge(key, data);

return data;
}

async getStats(metric) {
const result = await codebolt.dbmemory.getKnowledge(`aggregate:${metric}`);
const data = result.value;

if (!data || data.count === 0) {
return null;
}

return {
count: data.count,
sum: data.sum,
average: data.sum / data.count,
min: data.min,
max: data.max,
lastValue: data.values[data.values.length - 1]
};
}

async getTrend(metric, points = 10) {
const result = await codebolt.dbmemory.getKnowledge(`aggregate:${metric}`);
const data = result.value;

if (!data || data.values.length < points) {
return null;
}

// Get last N points
const recent = data.values.slice(-points);
const trend = recent.map(v => v.value);

// Calculate trend direction
const first = trend[0];
const last = trend[trend.length - 1];
const direction = last > first ? 'up' : last < first ? 'down' : 'stable';

return { trend, direction };
}
}

// Usage
const aggregator = new DataAggregator();

// Add data points
await aggregator.addDataPoint('response_time', 150);
await aggregator.addDataPoint('response_time', 200);
await aggregator.addDataPoint('response_time', 175);

// Get statistics
const stats = await aggregator.getStats('response_time');
console.log('Average response time:', stats.average);

// Get trend
const trend = await aggregator.getTrend('response_time', 10);
console.log('Trend:', trend.direction);

Module Integration Examples

Integration with State Module

async function syncStateToMemory() {
// Get project state
const projectState = await codebolt.cbstate.getProjectState();

// Cache in memory for fast access
await codebolt.dbmemory.addKnowledge(
'cache:project_config',
projectState.projectState.state
);

console.log('✅ Project state cached in memory');
return projectState;
}

Integration with Debug Module

async function debugMemoryUsage() {
// Get memory cache info
const cacheKey = 'cache:users';
const result = await codebolt.dbmemory.getKnowledge(cacheKey);

if (result.value) {
await codebolt.debug.debug(
`Memory cache hit for ${cacheKey}: ${JSON.stringify(result.value).length} bytes`,
'info'
);
} else {
await codebolt.debug.debug(`Memory cache miss for ${cacheKey}`, 'warning');
}
}

Integration with History Module

async function cacheConversationHistory() {
// Get conversation summary
const summary = await codebolt.history.summarizeAll();

// Cache in memory for quick access
await codebolt.dbmemory.addKnowledge(
'cache:conversation_summary',
{
summary,
cachedAt: new Date().toISOString()
}
);

return summary;
}

Best Practices

1. Use Namespaced Keys

// ✅ Good: Namespaced keys
await codebolt.dbmemory.addKnowledge('user:123:profile', userData);
await codebolt.dbmemory.addKnowledge('user:123:preferences', preferences);
await codebolt.dbmemory.addKnowledge('cache:api:users', userList);

// ❌ Bad: Non-descriptive keys
await codebolt.dbmemory.addKnowledge('data1', userData);
await codebolt.dbmemory.addKnowledge('data2', preferences);

2. Implement TTL for Cache

// ✅ Good: Cache with TTL
async function getCachedData(key, ttlMs) {
const cached = await codebolt.dbmemory.getKnowledge(`cache:${key}`);

if (cached.value && Date.now() - cached.value.timestamp < ttlMs) {
return cached.value.data;
}

return null;
}

// ❌ Bad: Cache without expiration
await codebolt.dbmemory.addKnowledge('cache:data', data);
// Data never expires, can become stale

3. Handle Cache Misses Gracefully

// ✅ Good: Handle cache misses
async function getDataWithFallback(key) {
const cached = await codebolt.dbmemory.getKnowledge(key);

if (cached.value) {
return cached.value;
}

// Fallback to source
return await fetchFromSource();
}

// ❌ Bad: Assume cache exists
const data = (await codebolt.dbmemory.getKnowledge(key)).value;
// Throws error if cache doesn't exist

4. Clean Up Expired Data

// ✅ Good: Regular cleanup
async function cleanupExpiredCache() {
const now = Date.now();
const ttl = 3600000; // 1 hour

// Check and clean cache entries
const keys = ['cache:users', 'cache:posts', 'cache:comments'];

for (const key of keys) {
const result = await codebolt.dbmemory.getKnowledge(key);
if (result.value && result.value.timestamp) {
if (now - result.value.timestamp > ttl) {
await codebolt.dbmemory.addKnowledge(key, null);
}
}
}
}

5. Use Structured Data

// ✅ Good: Structured data with metadata
await codebolt.dbmemory.addKnowledge('session:user_123', {
userId: 'user_123',
data: { /* session data */ },
metadata: {
createdAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 3600000).toISOString()
}
});

// ❌ Bad: Flat data without metadata
await codebolt.dbmemory.addKnowledge('session:user_123', sessionData);
// No way to track creation or expiration

Performance Considerations

Memory Usage

// Monitor memory usage
async function checkMemorySize() {
const keys = ['cache:users', 'cache:posts', 'cache:comments'];
let totalSize = 0;

for (const key of keys) {
const result = await codebolt.dbmemory.getKnowledge(key);
if (result.value) {
const size = JSON.stringify(result.value).length;
totalSize += size;
console.log(`${key}: ${size} bytes`);
}
}

console.log(`Total memory usage: ${totalSize} bytes`);
return totalSize;
}

Batch Operations

// ✅ Good: Batch operations
async function batchCache(items) {
const promises = items.map(item =>
codebolt.dbmemory.addKnowledge(item.key, item.value)
);
await Promise.all(promises);
}

// ❌ Bad: Sequential operations
for (const item of items) {
await codebolt.dbmemory.addKnowledge(item.key, item.value);
}

Common Pitfalls

Pitfall 1: No Expiration Strategy

// ❌ Problem: Data never expires
await codebolt.dbmemory.addKnowledge('cache:data', expensiveData);

// ✅ Solution: Implement TTL
async function setWithTTL(key, value, ttl) {
await codebolt.dbmemory.addKnowledge(key, {
value,
expiresAt: Date.now() + ttl
});
}

Pitfall 2: Race Conditions

// ❌ Problem: Concurrent updates
const data = await codebolt.dbmemory.getKnowledge('counter');
data.value.count++;
await codebolt.dbmemory.addKnowledge('counter', data.value);

// ✅ Solution: Use atomic operations
async function incrementCounter(key) {
const current = await codebolt.dbmemory.getKnowledge(key);
const newValue = (current.value?.count || 0) + 1;
await codebolt.dbmemory.addKnowledge(key, { count: newValue });
return newValue;
}

Pitfall 3: Memory Leaks

// ❌ Problem: Unbounded growth
for (let i = 0; i < 10000; i++) {
await codebolt.dbmemory.addKnowledge(`item_${i}`, largeObject);
}

// ✅ Solution: Implement size limits
class BoundedCache {
constructor(maxSize = 1000) {
this.maxSize = maxSize;
}

async set(key, value) {
// Check size and evict if needed
const currentKeys = await this.getCurrentKeys();
if (currentKeys.length >= this.maxSize) {
await this.evictOldest();
}

await codebolt.dbmemory.addKnowledge(key, {
value,
timestamp: Date.now()
});
}
}

Pitfall 4: Storing Large Objects

// ❌ Problem: Storing very large objects
await codebolt.dbmemory.addKnowledge('large_data', hugeArray);

// ✅ Solution: Split into chunks
async function storeLargeData(key, largeObject) {
const json = JSON.stringify(largeObject);
const chunkSize = 100000; // 100KB chunks
const chunks = [];

for (let i = 0; i < json.length; i += chunkSize) {
chunks.push(json.substring(i, i + chunkSize));
}

await codebolt.dbmemory.addKnowledge(`${key}:meta`, {
chunks: chunks.length,
originalSize: json.length
});

for (let i = 0; i < chunks.length; i++) {
await codebolt.dbmemory.addKnowledge(`${key}:chunk_${i}`, chunks[i]);
}
}