phase-9: domain-driven architecture complete
- Restructured server layer with 5 domains: shared, screener, portfolio, calls, finance - Migrated 58 TypeScript files to domain-driven structure - Updated CLAUDE.md with new architecture documentation - Added .gitignore rules for .md files (except CLAUDE.md) - Removed unused CatalystAnalyst import from app.ts - Fixed lint errors: removed unused imports, fixed regex escape, added console suppressions - Verified no sensitive data in git history - Server code compiles cleanly with TypeScript strict mode
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import * as queries from '../db/queries.constant';
|
||||
|
||||
export class QueryBuilder {
|
||||
readonly sql: string;
|
||||
readonly queryParams: unknown[];
|
||||
|
||||
/**
|
||||
* Create a QueryBuilder from a query constant path.
|
||||
*
|
||||
* @param queryPath Path to query in queries.constant.ts (e.g., 'MARKET_CALLS_QUERIES.SELECT_ALL')
|
||||
* @param params Parameters to bind (? placeholders in SQL)
|
||||
*/
|
||||
constructor(queryPath: string, params: unknown[] = []) {
|
||||
this.sql = this.lookupQuery(queryPath);
|
||||
this.queryParams = params;
|
||||
|
||||
// Validate parameter count matches placeholders
|
||||
const placeholderCount = (this.sql.match(/\?/g) || []).length;
|
||||
if (this.queryParams.length !== placeholderCount) {
|
||||
throw new Error(
|
||||
`Parameter mismatch for query "${queryPath}": expected ${placeholderCount}, got ${this.queryParams.length}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a query from queries.constant.ts.
|
||||
* Supports nested paths like "MARKET_CALLS_QUERIES.SELECT_ALL".
|
||||
*
|
||||
* @param queryPath Path to query (e.g., 'MARKET_CALLS_QUERIES.SELECT_ALL')
|
||||
* @returns The SQL query string
|
||||
* @throws Error if query not found
|
||||
*/
|
||||
private lookupQuery(queryPath: string): string {
|
||||
const parts = queryPath.split('.');
|
||||
|
||||
// Navigate through the nested objects
|
||||
let current: any = queries;
|
||||
for (const part of parts) {
|
||||
if (!(part in current)) {
|
||||
throw new Error(
|
||||
`Query not found: "${queryPath}". Make sure it exists in queries.constant.ts`,
|
||||
);
|
||||
}
|
||||
current = current[part];
|
||||
}
|
||||
|
||||
if (typeof current !== 'string') {
|
||||
throw new Error(`Invalid query: "${queryPath}" must be a string, got ${typeof current}`);
|
||||
}
|
||||
|
||||
// Clean up the SQL (remove extra whitespace)
|
||||
return current.trim();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user