fix(orm): add explicit PostgreSQL column types for all ORM entities

- user-service: user.orm.ts (lastActiveAt), verification-code.orm.ts (all fields)
- file-service: file.orm.ts (userId, originalName, storagePath, mimeType)
- conversation-service: token-usage.orm.ts (model, all token/count fields)
- knowledge-service: knowledge-article.orm.ts, knowledge-chunk.orm.ts,
  system-experience.orm.ts, user-memory.orm.ts (all numeric, boolean, date fields)

This fixes DataTypeNotSupportedError where PostgreSQL rejects "Object" type
when @Column decorator lacks explicit type specification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-25 02:14:07 -08:00
parent a1f4f7ba0e
commit fe37267c39
8 changed files with 51 additions and 51 deletions

View File

@ -27,22 +27,22 @@ export class TokenUsageORM {
@Column({ name: 'message_id', type: 'uuid', nullable: true })
messageId: string | null;
@Column({ length: 50 })
@Column({ type: 'varchar', length: 50 })
model: string;
@Column({ name: 'input_tokens', default: 0 })
@Column({ name: 'input_tokens', type: 'int', default: 0 })
inputTokens: number;
@Column({ name: 'output_tokens', default: 0 })
@Column({ name: 'output_tokens', type: 'int', default: 0 })
outputTokens: number;
@Column({ name: 'cache_creation_tokens', default: 0 })
@Column({ name: 'cache_creation_tokens', type: 'int', default: 0 })
cacheCreationTokens: number;
@Column({ name: 'cache_read_tokens', default: 0 })
@Column({ name: 'cache_read_tokens', type: 'int', default: 0 })
cacheReadTokens: number;
@Column({ name: 'total_tokens', default: 0 })
@Column({ name: 'total_tokens', type: 'int', default: 0 })
totalTokens: number;
@Column({ name: 'estimated_cost', type: 'decimal', precision: 10, scale: 6, default: 0 })
@ -51,13 +51,13 @@ export class TokenUsageORM {
@Column({ name: 'intent_type', type: 'varchar', length: 30, nullable: true })
intentType: string | null;
@Column({ name: 'tool_calls', default: 0 })
@Column({ name: 'tool_calls', type: 'int', default: 0 })
toolCalls: number;
@Column({ name: 'response_length', default: 0 })
@Column({ name: 'response_length', type: 'int', default: 0 })
responseLength: number;
@Column({ name: 'latency_ms', default: 0 })
@Column({ name: 'latency_ms', type: 'int', default: 0 })
latencyMs: number;
@CreateDateColumn({ name: 'created_at' })

View File

@ -14,7 +14,7 @@ export class FileORM {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'user_id' })
@Column({ name: 'user_id', type: 'uuid' })
@Index()
userId: string;
@ -22,13 +22,13 @@ export class FileORM {
@Index()
conversationId: string | null;
@Column({ name: 'original_name' })
@Column({ name: 'original_name', type: 'varchar', length: 500 })
originalName: string;
@Column({ name: 'storage_path' })
@Column({ name: 'storage_path', type: 'varchar', length: 1000 })
storagePath: string;
@Column({ name: 'mime_type' })
@Column({ name: 'mime_type', type: 'varchar', length: 100 })
mimeType: string;
@Column({ type: 'varchar', length: 50 })

View File

@ -30,7 +30,7 @@ export class KnowledgeArticleORM {
@PrimaryColumn('uuid')
id: string;
@Column({ length: 500 })
@Column({ type: 'varchar', length: 500 })
title: string;
@Column('text')
@ -39,16 +39,16 @@ export class KnowledgeArticleORM {
@Column('text', { nullable: true })
summary: string;
@Column({ length: 50 })
@Column({ type: 'varchar', length: 50 })
category: string;
@Column('text', { array: true, default: '{}' })
tags: string[];
@Column({ length: 20 })
@Column({ type: 'varchar', length: 20 })
source: string;
@Column({ name: 'source_url', length: 1000, nullable: true })
@Column({ name: 'source_url', type: 'varchar', length: 1000, nullable: true })
sourceUrl?: string;
@Column({
@ -58,25 +58,25 @@ export class KnowledgeArticleORM {
})
embedding?: number[];
@Column({ name: 'is_published', default: false })
@Column({ name: 'is_published', type: 'boolean', default: false })
isPublished: boolean;
@Column({ name: 'citation_count', default: 0 })
@Column({ name: 'citation_count', type: 'int', default: 0 })
citationCount: number;
@Column({ name: 'helpful_count', default: 0 })
@Column({ name: 'helpful_count', type: 'int', default: 0 })
helpfulCount: number;
@Column({ name: 'unhelpful_count', default: 0 })
@Column({ name: 'unhelpful_count', type: 'int', default: 0 })
unhelpfulCount: number;
@Column({ name: 'quality_score', default: 50 })
@Column({ name: 'quality_score', type: 'int', default: 50 })
qualityScore: number;
@Column({ name: 'created_by', nullable: true })
@Column({ name: 'created_by', type: 'varchar', length: 100, nullable: true })
createdBy?: string;
@Column({ name: 'updated_by', nullable: true })
@Column({ name: 'updated_by', type: 'varchar', length: 100, nullable: true })
updatedBy?: string;
@CreateDateColumn({ name: 'created_at' })

View File

@ -28,16 +28,16 @@ export class KnowledgeChunkORM {
@PrimaryColumn('uuid')
id: string;
@Column({ name: 'article_id' })
@Column({ name: 'article_id', type: 'uuid' })
articleId: string;
@Column('text')
content: string;
@Column({ name: 'chunk_index' })
@Column({ name: 'chunk_index', type: 'int' })
chunkIndex: number;
@Column({ name: 'chunk_type', length: 20 })
@Column({ name: 'chunk_type', type: 'varchar', length: 20 })
chunkType: string;
@Column({
@ -50,7 +50,7 @@ export class KnowledgeChunkORM {
@Column('jsonb', { default: '{}' })
metadata: Record<string, unknown>;
@Column({ name: 'token_count', default: 0 })
@Column({ name: 'token_count', type: 'int', default: 0 })
tokenCount: number;
@CreateDateColumn({ name: 'created_at' })

View File

@ -31,40 +31,40 @@ export class SystemExperienceORM {
@PrimaryColumn('uuid')
id: string;
@Column({ name: 'experience_type', length: 30 })
@Column({ name: 'experience_type', type: 'varchar', length: 30 })
experienceType: string;
@Column('text')
content: string;
@Column({ default: 50 })
@Column({ type: 'int', default: 50 })
confidence: number;
@Column('text')
scenario: string;
@Column({ name: 'related_category', length: 50, nullable: true })
@Column({ name: 'related_category', type: 'varchar', length: 50, nullable: true })
relatedCategory?: string;
@Column('text', { name: 'source_conversation_ids', array: true, default: '{}' })
sourceConversationIds: string[];
@Column({ name: 'verification_status', length: 20, default: 'PENDING' })
@Column({ name: 'verification_status', type: 'varchar', length: 20, default: 'PENDING' })
verificationStatus: string;
@Column({ name: 'verified_by', nullable: true })
@Column({ name: 'verified_by', type: 'varchar', length: 100, nullable: true })
verifiedBy?: string;
@Column({ name: 'verified_at', nullable: true })
@Column({ name: 'verified_at', type: 'timestamptz', nullable: true })
verifiedAt?: Date;
@Column({ name: 'usage_count', default: 0 })
@Column({ name: 'usage_count', type: 'int', default: 0 })
usageCount: number;
@Column({ name: 'positive_count', default: 0 })
@Column({ name: 'positive_count', type: 'int', default: 0 })
positiveCount: number;
@Column({ name: 'negative_count', default: 0 })
@Column({ name: 'negative_count', type: 'int', default: 0 })
negativeCount: number;
@Column({
@ -74,7 +74,7 @@ export class SystemExperienceORM {
})
embedding?: number[];
@Column({ name: 'is_active', default: false })
@Column({ name: 'is_active', type: 'boolean', default: false })
isActive: boolean;
@CreateDateColumn({ name: 'created_at' })

View File

@ -31,22 +31,22 @@ export class UserMemoryORM {
@PrimaryColumn('uuid')
id: string;
@Column({ name: 'user_id' })
@Column({ name: 'user_id', type: 'uuid' })
userId: string;
@Column({ name: 'memory_type', length: 30 })
@Column({ name: 'memory_type', type: 'varchar', length: 30 })
memoryType: string;
@Column('text')
content: string;
@Column({ default: 50 })
@Column({ type: 'int', default: 50 })
importance: number;
@Column({ name: 'source_conversation_id', nullable: true })
@Column({ name: 'source_conversation_id', type: 'uuid', nullable: true })
sourceConversationId?: string;
@Column({ name: 'related_category', length: 50, nullable: true })
@Column({ name: 'related_category', type: 'varchar', length: 50, nullable: true })
relatedCategory?: string;
@Column({
@ -56,13 +56,13 @@ export class UserMemoryORM {
})
embedding?: number[];
@Column({ name: 'access_count', default: 0 })
@Column({ name: 'access_count', type: 'int', default: 0 })
accessCount: number;
@Column({ name: 'last_accessed_at', nullable: true })
@Column({ name: 'last_accessed_at', type: 'timestamptz', nullable: true })
lastAccessedAt?: Date;
@Column({ name: 'is_expired', default: false })
@Column({ name: 'is_expired', type: 'boolean', default: false })
isExpired: boolean;
@CreateDateColumn({ name: 'created_at' })

View File

@ -40,6 +40,6 @@ export class UserORM {
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
@Column({ name: 'last_active_at', default: () => 'NOW()' })
@Column({ name: 'last_active_at', type: 'timestamptz', default: () => 'NOW()' })
lastActiveAt: Date;
}

View File

@ -14,16 +14,16 @@ export class VerificationCodeORM {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
@Column({ type: 'varchar', length: 20 })
phone: string;
@Column()
@Column({ type: 'varchar', length: 10 })
code: string;
@Column({ name: 'expires_at' })
@Column({ name: 'expires_at', type: 'timestamptz' })
expiresAt: Date;
@Column({ name: 'is_used', default: false })
@Column({ name: 'is_used', type: 'boolean', default: false })
isUsed: boolean;
@CreateDateColumn({ name: 'created_at' })