fixed mongo

This commit is contained in:
Bojan Kucera 2025-06-09 20:19:25 -04:00
parent c172ecc6d3
commit 2437628591
5 changed files with 133 additions and 130 deletions

View file

@ -12,7 +12,8 @@
"type-check": "tsc --noEmit",
"clean": "rimraf dist"
},
"dependencies": { "@stock-bot/config": "*",
"dependencies": {
"@stock-bot/config": "*",
"@stock-bot/logger": "*",
"@stock-bot/types": "*",
"mongodb": "^6.3.0",

View file

@ -15,7 +15,7 @@ import type {
} from './types';
import { MongoDBHealthMonitor } from './health';
import { schemaMap } from './schemas';
import { z } from 'zod';
import * as yup from 'yup';
/**
* MongoDB Client for Stock Bot
@ -147,15 +147,15 @@ export class MongoDBClient {
} as T; // Validate document if schema exists
if (collectionName in schemaMap) {
try {
(schemaMap as any)[collectionName].parse(docWithTimestamps);
(schemaMap as any)[collectionName].validateSync(docWithTimestamps);
} catch (error) {
if (error instanceof z.ZodError) {
if (error instanceof yup.ValidationError) {
this.logger.error(`Document validation failed for ${collectionName}:`, error.errors);
throw new Error(`Document validation failed: ${error.errors.map(e => e.message).join(', ')}`);
throw new Error(`Document validation failed: ${error.errors?.map(e => e).join(', ')}`);
}
throw error;
}
} const result = await collection.insertOne(docWithTimestamps as OptionalUnlessRequiredId<T>);
}const result = await collection.insertOne(docWithTimestamps as OptionalUnlessRequiredId<T>);
return { ...docWithTimestamps, _id: result.insertedId } as T;
}

View file

@ -1,124 +1,124 @@
import * as yup from 'yup';
/**
* Zod Schemas for MongoDB Document Validation
* Yup Schemas for MongoDB Document Validation
*/
// Base schema for all documents
export const documentBaseSchema = z.object({
_id: z.any().optional(),
created_at: z.date(),
updated_at: z.date(),
source: z.string(),
metadata: z.record(z.any()).optional(),
export const documentBaseSchema = yup.object({
_id: yup.mixed().optional(),
created_at: yup.date().required(),
updated_at: yup.date().required(),
source: yup.string().required(),
metadata: yup.object().optional(),
});
// Sentiment Data Schema
export const sentimentDataSchema = documentBaseSchema.extend({
symbol: z.string().min(1).max(10),
sentiment_score: z.number().min(-1).max(1),
sentiment_label: z.enum(['positive', 'negative', 'neutral']),
confidence: z.number().min(0).max(1),
text: z.string().min(1),
source_type: z.enum(['reddit', 'twitter', 'news', 'forums']),
source_id: z.string(),
timestamp: z.date(),
processed_at: z.date(),
language: z.string().default('en'),
keywords: z.array(z.string()),
entities: z.array(z.object({
name: z.string(),
type: z.string(),
confidence: z.number().min(0).max(1),
})),
export const sentimentDataSchema = documentBaseSchema.shape({
symbol: yup.string().min(1).max(10).required(),
sentiment_score: yup.number().min(-1).max(1).required(),
sentiment_label: yup.string().oneOf(['positive', 'negative', 'neutral']).required(),
confidence: yup.number().min(0).max(1).required(),
text: yup.string().min(1).required(),
source_type: yup.string().oneOf(['reddit', 'twitter', 'news', 'forums']).required(),
source_id: yup.string().required(),
timestamp: yup.date().required(),
processed_at: yup.date().required(),
language: yup.string().default('en'),
keywords: yup.array(yup.string()).required(),
entities: yup.array(yup.object({
name: yup.string().required(),
type: yup.string().required(),
confidence: yup.number().min(0).max(1).required(),
})).required(),
});
// Raw Document Schema
export const rawDocumentSchema = documentBaseSchema.extend({
document_type: z.enum(['html', 'pdf', 'text', 'json', 'xml']),
content: z.string(),
content_hash: z.string(),
url: z.string().url().optional(),
title: z.string().optional(),
author: z.string().optional(),
published_date: z.date().optional(),
extracted_text: z.string().optional(),
processing_status: z.enum(['pending', 'processed', 'failed']),
size_bytes: z.number().positive(),
language: z.string().optional(),
export const rawDocumentSchema = documentBaseSchema.shape({
document_type: yup.string().oneOf(['html', 'pdf', 'text', 'json', 'xml']).required(),
content: yup.string().required(),
content_hash: yup.string().required(),
url: yup.string().url().optional(),
title: yup.string().optional(),
author: yup.string().optional(),
published_date: yup.date().optional(),
extracted_text: yup.string().optional(),
processing_status: yup.string().oneOf(['pending', 'processed', 'failed']).required(),
size_bytes: yup.number().positive().required(),
language: yup.string().optional(),
});
// News Article Schema
export const newsArticleSchema = documentBaseSchema.extend({
headline: z.string().min(1),
content: z.string().min(1),
summary: z.string().optional(),
author: z.string(),
publication: z.string(),
published_date: z.date(),
url: z.string().url(),
symbols: z.array(z.string()),
categories: z.array(z.string()),
sentiment_score: z.number().min(-1).max(1).optional(),
relevance_score: z.number().min(0).max(1).optional(),
image_url: z.string().url().optional(),
tags: z.array(z.string()),
export const newsArticleSchema = documentBaseSchema.shape({
headline: yup.string().min(1).required(),
content: yup.string().min(1).required(),
summary: yup.string().optional(),
author: yup.string().required(),
publication: yup.string().required(),
published_date: yup.date().required(),
url: yup.string().url().required(),
symbols: yup.array(yup.string()).required(),
categories: yup.array(yup.string()).required(),
sentiment_score: yup.number().min(-1).max(1).optional(),
relevance_score: yup.number().min(0).max(1).optional(),
image_url: yup.string().url().optional(),
tags: yup.array(yup.string()).required(),
});
// SEC Filing Schema
export const secFilingSchema = documentBaseSchema.extend({
cik: z.string(),
accession_number: z.string(),
filing_type: z.string(),
company_name: z.string(),
symbols: z.array(z.string()),
filing_date: z.date(),
period_end_date: z.date(),
url: z.string().url(),
content: z.string(),
extracted_data: z.record(z.any()).optional(),
financial_statements: z.array(z.object({
statement_type: z.string(),
data: z.record(z.number()),
export const secFilingSchema = documentBaseSchema.shape({
cik: yup.string().required(),
accession_number: yup.string().required(),
filing_type: yup.string().required(),
company_name: yup.string().required(),
symbols: yup.array(yup.string()).required(),
filing_date: yup.date().required(),
period_end_date: yup.date().required(),
url: yup.string().url().required(),
content: yup.string().required(),
extracted_data: yup.object().optional(),
financial_statements: yup.array(yup.object({
statement_type: yup.string().required(),
data: yup.object().required(),
})).optional(),
processing_status: z.enum(['pending', 'processed', 'failed']),
processing_status: yup.string().oneOf(['pending', 'processed', 'failed']).required(),
});
// Earnings Transcript Schema
export const earningsTranscriptSchema = documentBaseSchema.extend({
symbol: z.string().min(1).max(10),
company_name: z.string(),
quarter: z.string(),
year: z.number().min(2000).max(3000),
call_date: z.date(),
transcript: z.string(),
participants: z.array(z.object({
name: z.string(),
title: z.string(),
type: z.enum(['executive', 'analyst']),
})),
key_topics: z.array(z.string()),
sentiment_analysis: z.object({
overall_sentiment: z.number().min(-1).max(1),
topic_sentiments: z.record(z.number()),
export const earningsTranscriptSchema = documentBaseSchema.shape({
symbol: yup.string().min(1).max(10).required(),
company_name: yup.string().required(),
quarter: yup.string().required(),
year: yup.number().min(2000).max(3000).required(),
call_date: yup.date().required(),
transcript: yup.string().required(),
participants: yup.array(yup.object({
name: yup.string().required(),
title: yup.string().required(),
type: yup.string().oneOf(['executive', 'analyst']).required(),
})).required(),
key_topics: yup.array(yup.string()).required(),
sentiment_analysis: yup.object({
overall_sentiment: yup.number().min(-1).max(1).required(),
topic_sentiments: yup.object().required(),
}).optional(),
financial_highlights: z.record(z.number()).optional(),
financial_highlights: yup.object().optional(),
});
// Analyst Report Schema
export const analystReportSchema = documentBaseSchema.extend({
symbol: z.string().min(1).max(10),
analyst_firm: z.string(),
analyst_name: z.string(),
report_title: z.string(),
report_date: z.date(),
rating: z.enum(['buy', 'hold', 'sell', 'strong_buy', 'strong_sell']),
price_target: z.number().positive().optional(),
previous_rating: z.string().optional(),
content: z.string(),
summary: z.string(),
key_points: z.array(z.string()),
financial_projections: z.record(z.number()).optional(),
export const analystReportSchema = documentBaseSchema.shape({
symbol: yup.string().min(1).max(10).required(),
analyst_firm: yup.string().required(),
analyst_name: yup.string().required(),
report_title: yup.string().required(),
report_date: yup.date().required(),
rating: yup.string().oneOf(['buy', 'hold', 'sell', 'strong_buy', 'strong_sell']).required(),
price_target: yup.number().positive().optional(),
previous_rating: yup.string().optional(),
content: yup.string().required(),
summary: yup.string().required(),
key_points: yup.array(yup.string()).required(),
financial_projections: yup.object().optional(),
});
// Schema mapping for collections