Initial Commit

This commit is contained in:
Eric Gullickson
2025-09-17 16:09:15 -05:00
parent 0cdb9803de
commit a052040e3a
373 changed files with 437090 additions and 6773 deletions

View File

@@ -0,0 +1,97 @@
/**
* @ai-summary Database operations for user preferences
* @ai-context Repository pattern for user preference CRUD operations
*/
import { Pool } from 'pg';
import { UserPreferences, CreateUserPreferencesRequest, UpdateUserPreferencesRequest } from '../user-preferences.types';
export class UserPreferencesRepository {
constructor(private db: Pool) {}
async findByUserId(userId: string): Promise<UserPreferences | null> {
const query = `
SELECT id, user_id, unit_system, currency_code, time_zone, created_at, updated_at
FROM user_preferences
WHERE user_id = $1
`;
const result = await this.db.query(query, [userId]);
return result.rows.length > 0 ? this.mapRow(result.rows[0]) : null;
}
async create(data: CreateUserPreferencesRequest): Promise<UserPreferences> {
const query = `
INSERT INTO user_preferences (user_id, unit_system, currency_code, time_zone)
VALUES ($1, $2, $3, $4)
RETURNING *
`;
const values = [
data.userId,
data.unitSystem || 'imperial',
(data as any).currencyCode || 'USD',
(data as any).timeZone || 'UTC'
];
const result = await this.db.query(query, values);
return this.mapRow(result.rows[0]);
}
async update(userId: string, data: UpdateUserPreferencesRequest): Promise<UserPreferences | null> {
const fields = [];
const values = [];
let paramCount = 1;
if (data.unitSystem !== undefined) {
fields.push(`unit_system = $${paramCount++}`);
values.push(data.unitSystem);
}
if ((data as any).currencyCode !== undefined) {
fields.push(`currency_code = $${paramCount++}`);
values.push((data as any).currencyCode);
}
if ((data as any).timeZone !== undefined) {
fields.push(`time_zone = $${paramCount++}`);
values.push((data as any).timeZone);
}
if (fields.length === 0) {
return this.findByUserId(userId);
}
const query = `
UPDATE user_preferences
SET ${fields.join(', ')}, updated_at = CURRENT_TIMESTAMP
WHERE user_id = $${paramCount}
RETURNING *
`;
values.push(userId);
const result = await this.db.query(query, values);
return result.rows.length > 0 ? this.mapRow(result.rows[0]) : null;
}
async upsert(data: CreateUserPreferencesRequest): Promise<UserPreferences> {
const existing = await this.findByUserId(data.userId);
if (existing) {
const updated = await this.update(data.userId, { unitSystem: data.unitSystem });
return updated!;
}
return this.create(data);
}
private mapRow(row: any): UserPreferences {
return {
id: row.id,
userId: row.user_id,
unitSystem: row.unit_system,
currencyCode: row.currency_code || 'USD',
timeZone: row.time_zone || 'UTC',
createdAt: row.created_at,
updatedAt: row.updated_at,
};
}
}

View File

@@ -0,0 +1,19 @@
-- Create user_preferences table for storing user settings
CREATE TYPE unit_system AS ENUM ('imperial', 'metric');
CREATE TABLE IF NOT EXISTS user_preferences (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id VARCHAR(255) UNIQUE NOT NULL,
unit_system unit_system NOT NULL DEFAULT 'imperial',
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Create indexes
CREATE INDEX idx_user_preferences_user_id ON user_preferences(user_id);
-- Add trigger for updated_at
CREATE TRIGGER update_user_preferences_updated_at
BEFORE UPDATE ON user_preferences
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

View File

@@ -0,0 +1,7 @@
-- Add currency_code and time_zone to user_preferences
ALTER TABLE user_preferences
ADD COLUMN IF NOT EXISTS currency_code VARCHAR(3) DEFAULT 'USD',
ADD COLUMN IF NOT EXISTS time_zone VARCHAR(100) DEFAULT 'UTC';
-- Optional: basic length/format checks can be enforced at application layer

View File

@@ -0,0 +1,37 @@
/**
* @ai-summary Type definitions for user preferences system
* @ai-context Manages user settings including unit preferences
*/
export type UnitSystem = 'imperial' | 'metric';
export interface UserPreferences {
id: string;
userId: string;
unitSystem: UnitSystem;
currencyCode: string;
timeZone: string;
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserPreferencesRequest {
userId: string;
unitSystem?: UnitSystem;
}
export interface UpdateUserPreferencesRequest {
unitSystem?: UnitSystem;
currencyCode?: string;
timeZone?: string;
}
export interface UserPreferencesResponse {
id: string;
userId: string;
unitSystem: UnitSystem;
currencyCode: string;
timeZone: string;
createdAt: string;
updatedAt: string;
}