import {logger} from '@orion-js/logger'
import {MigrationService} from '@orion-js/migrations'
import {createCollection} from '@orion-js/mongodb'
import {Inject} from '@orion-js/services'
import {CalculateCallerPlanTypeService} from 'app/ai/services/CalculateCallerPlanType'
/**
* Local interface for the document structure we're migrating.
* Keeps the migration decoupled from schema changes.
*/
interface GenerationLogCaller {
userId?: string
organizationId?: string
isAnonymous?: boolean
}
interface GenerationLogDoc {
_id: string
caller?: GenerationLogCaller
}
/**
* Migration to set planType and planId for all existing GenerationLogs.
* Uses current subscription status since all logs were generated recently.
*/
@MigrationService({
name: 'MigrateGenerationLogsPlanType.v1',
useMongoTransactions: false,
})
export class MigrateGenerationLogsPlanType {
// Direct collection access is allowed during migrations
private collection = createCollection({name: 'ai.generation_logs'})
@Inject(() => CalculateCallerPlanTypeService)
private calculateCallerPlanTypeService: CalculateCallerPlanTypeService
async runMigration() {
// Only fetch documents that need updating
const cursor = this.collection.find({
'caller.planType': {$exists: false},
})
let processed = 0
let updated = 0
// Process documents in a cursor loop to avoid memory issues
for await (const doc of cursor) {
const log = doc as GenerationLogDoc
const planInfo = await this.calculateCallerPlanTypeService.execute(log.caller)
await this.collection.updateOne(
{_id: log._id},
{
$set: {
'caller.planType': planInfo.planType,
...(planInfo.planId && {'caller.planId': planInfo.planId}),
},
},
)
updated++
processed++
// Log progress every 500 documents
if (processed % 500 === 0) {
logger.info('Migration progress', {processed, updated})
}
}
logger.info('MigrateGenerationLogsPlanType complete', {processed, updated})
}
}