Skip to content

Commit

Permalink
Improve default story tree formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
maxhniebergall committed Dec 30, 2024
1 parent adbf119 commit f43e1fd
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 15 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ docker-compose -f docker-compose.prod.yml logs -f

### Stop services
docker-compose -f docker-compose.prod.yml down


# Seed database
## In Development:
curl -X POST http://localhost:3000/api/seed-default-stories -H "Content-Type: application/json" -d '{}'
75 changes: 70 additions & 5 deletions backend/prodSeed.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/*
Requirements:
- Must create proper story tree nodes for each text entry
- Must maintain unique IDs for each node
- Must properly link parent and child nodes
- Must preserve metadata across all nodes
- Must use Redis database client for storage
- Must handle error cases gracefully
*/

import newLogger from './logger.js';

const logger = newLogger("prodSeed.js");
Expand Down Expand Up @@ -25,16 +35,44 @@ const DEFAULT_STORY_TREES = [
},
{
id: 'default-3',
text: '1: a concise statement of a principle\n2: a terse formulation of a truth or sentiment : adage\n\n- https://www.merriam-webster.com/dictionary/aphorism',
title: 'An aphorism',
text: 'What is an aphorism?',
title: 'Aphorism',
childTexts: [
'An Aphorism a heurisitic which helps us to make good choices and communicate wisdom (Aphori.st)',
'An "aphorism" is a concise statement of a principle (https://www.merriam-webster.com/dictionary/aphorism)',
'An "aphorism" is terse formulation of a truth or sentiment (https://www.merriam-webster.com/dictionary/aphorism)',
],
nodes: [],
metadata: {
author: 'MaxHniebergall',
title: 'An aphorism'
title: 'Aphorism'
}
}
];

async function createStoryTreeNode(nodeId, content, childNodes, metadata, parentId = null) {
// Format nodes array to match frontend expectations
const nodes = childNodes.map(childId => ({
id: childId,
parentId: nodeId
}));

// Create the full object for returning to API
const storyTree = {
id: nodeId,
text: content,
nodes: nodes,
parentId,
metadata: {
title: metadata.title,
author: metadata.author
},
totalNodes: nodes.length
};

return storyTree;
}

async function seedDefaultStories(db) {
try {
logger.info('Starting to seed default stories');
Expand All @@ -46,8 +84,35 @@ async function seedDefaultStories(db) {
if (!existing) {
logger.info(`Seeding default story: ${story.id}`);

// Store in database
await db.hSet(story.id, 'storyTree', JSON.stringify(story));
// Create child nodes if they exist
const childNodes = [];
if (story.childTexts && story.childTexts.length > 0) {
let counter = 0;
for (const childText of story.childTexts) {
const childId = `${story.id}-${counter}`;
const childNode = await createStoryTreeNode(
childId,
childText,
[], // No grandchildren for now
story.metadata,
story.id
);
childNodes.push(childId);
counter +=1

// Store child node
await db.hSet(childId, 'storyTree', JSON.stringify(childNode));
}
}

// Create and store parent node
const parentNode = await createStoryTreeNode(
story.id,
story.text,
childNodes,
story.metadata
);
await db.hSet(story.id, 'storyTree', JSON.stringify(parentNode));

// Add to feed items
const feedItem = {
Expand Down
18 changes: 9 additions & 9 deletions backend/server.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* requirements
- getUserById checks id with tolowercase
*/

import express, { json } from "express";
import { createDatabaseClient } from './db/index.js';
import newLogger from './logger.js';
Expand Down Expand Up @@ -98,8 +102,9 @@ await db.connect().then(() => {
isDbReady = true;
// Only seed development stories in non-production environments
if (process.env.NODE_ENV !== 'production') {
logger.info('Development environment detected, seeding dev stories...');
seedDevStories(db);
// logger.info('Development environment detected, seeding dev stories...');
logger.info('Development environment detected, seeding default stories...');
seedDefaultStories(db);
} else {
logger.info('Production environment detected, skipping dev seed');
}
Expand Down Expand Up @@ -246,13 +251,8 @@ const USER_IDS_SET = 'user_ids';
const EMAIL_TO_ID_PREFIX = 'email_to_id';

const getUserById = async (id) => {
const userData = await db.hGet(db.encodeKey(id, USER_PREFIX), 'data');
if (!userData) {
return {
success: false,
error: 'User not found'
};
}
const lowercaseId = id.toLowerCase();
const userData = await db.hGet(db.encodeKey(lowercaseId, USER_PREFIX), 'data');
return {
success: true,
data: userData // Already decompressed by the client
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/operators/BaseOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ export class BaseOperator {
console.log("BaseOperator: data is compressed as array of items");
return response.data.items.map((item) => this.decompressItem(item));
}


// If the entire response is compressed (legacy format)
console.log("BaseOperator: data is compressed as entire response");
return await compression.decompress(response.data);
} else if (response.data?.v ===1 && response.data?.c === false && response.data?.d) {
console.log("BaseOperator: data is encoded as entire response");
return compression.unencode(response.data.d);
} else {
console.log("BaseOperator: data is not compressed");
return response.data;
Expand All @@ -46,8 +50,17 @@ export class BaseOperator {
console.error('Error parsing decompressed item:', e);
return decompressedItem;
}
} else if (itemObject?.v === 1 && itemObject?.c === false && itemObject?.d) {
console.log("BaseOperator: data is encoded as item");
const unencodedItem = await compression.unencode(itemObject.d);
if (typeof unencodedItem === 'string') {
return JSON.parse(unencodedItem);
} else {
return unencodedItem;
}
}
return item;

return item;
}

// Helper method for retrying API calls
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/utils/compression.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ export class DatabaseCompression {
return text;
}
}

async unencode(value) {
if (typeof value !== 'string') {
return value;
}
const encoded = Buffer.from(value, 'base64');
const text = new TextDecoder().decode(encoded);
return JSON.parse(text);
}
}

// Create a singleton instance
Expand Down

0 comments on commit f43e1fd

Please sign in to comment.