<commit_before>class CourseMigrator
  attr_reader :course_id, :concurrency, :store

  def initialize(course_id, concurrency:, fix_id: true)
    @course_id = course_id
    @concurrency = concurrency
    @fix_id = fix_id
    @store = concurrency == 1 ? CachedWriteStore.new : RedisStore.new
  end

  def start
    new_course_id = if concurrency <= 1
                      single_thread_migrate
                    else
                      parallel_migrate
                    end

    Logger.log "Course #{@course_id} is migrated to #{new_course_id}" if new_course_id
  end

  private

  def single_thread_migrate
    Logger.log "Start migrating course #{course_id} ..."
    new_course_id = nil

    ::Course.transaction do
      results = tables.map(&:run)
      new_course_id = results[0][0] if results[0]
    end
    store.persist_to_redis

    new_course_id
  end

  def parallel_migrate
    Logger.log "Start migrating course #{course_id} using #{concurrency} processes..."
    new_course_id = nil

    begin
      started = []
      tables.each_with_index do |t, index|
        started << t
        ret = t.run
        # First table is the course table
        new_course_id = ret[0] if t.is_a?(CourseTable) && ret
      end
    rescue Exception => e
      Logger.log e.message
      Logger.log e.backtrace
      Logger.log "Migration of #{course_id} failed, rolling back and deleting target course #{new_course_id}"

      if new_course_id
        ensure_db_connection
        ::Course.find(new_course_id).destroy

        new_course_id = nil
      end
      started.each(&:rollback)
    end

    new_course_id
  end

  def tables
    @tables ||= begin
      ts = []
      ts << CourseTable.new(store, course_id, fix_id: @fix_id)

      ts += [
        CourseUserTable,
        AnnouncementTable,
        AchievementTable,
        LevelTable,
        ExpRecordTable,
        LessonPlanMilestoneTable,
        LessonPlanEventTable,

        ForumTable,
        ForumTopicTable,
        ForumTopicViewTable,
        ForumPostTable,
        ForumPostVoteTable,

        AssessmentTabTable,
        AssessmentTable,
        AssessmentMcqQuestionTable,
        AssessmentMcqOptionTable,
        AssessmentTrqQuestionTable,
        AssessmentTrqKeywordSolutionTable,
        AssessmentTrqExactMatchSolutionTable,
        AssessmentScribingQuestionTable,
        AssessmentProgrammingQuestionTable,

        AssessmentSubmissionTable,
        AssessmentMcqAnswerTable,
        AssessmentMcqAnswerOptionTable,
        AssessmentTrqAnswerTable,
        AssessmentScribingAnswerTable,
        AssessmentAnswerScribbleTable,
        AssessmentProgrammingAnswerTable,

        AssessmentSkillGroupTable,
        AssessmentSkillTable,
        AssessmentQuestionSkillTable,

        ConditionTable,
        AssessmentConditionTable,

        MaterialFolderTable,
        MaterialTable,

        SurveyTable,
        SurveySectionTable,
        SurveyQuestionTable,<commit_msg>Add missing tables<commit_after>class CourseMigrator
  attr_reader :course_id, :concurrency, :store

  def initialize(course_id, concurrency:, fix_id: true)
    @course_id = course_id
    @concurrency = concurrency
    @fix_id = fix_id
    @store = concurrency == 1 ? CachedWriteStore.new : RedisStore.new
  end

  def start
    new_course_id = if concurrency <= 1
                      single_thread_migrate
                    else
                      parallel_migrate
                    end

    Logger.log "Course #{@course_id} is migrated to #{new_course_id}" if new_course_id
  end

  private

  def single_thread_migrate
    Logger.log "Start migrating course #{course_id} ..."
    new_course_id = nil

    ::Course.transaction do
      results = tables.map(&:run)
      new_course_id = results[0][0] if results[0]
    end
    store.persist_to_redis

    new_course_id
  end

  def parallel_migrate
    Logger.log "Start migrating course #{course_id} using #{concurrency} processes..."
    new_course_id = nil

    begin
      started = []
      tables.each_with_index do |t, index|
        started << t
        ret = t.run
        # First table is the course table
        new_course_id = ret[0] if t.is_a?(CourseTable) && ret
      end
    rescue Exception => e
      Logger.log e.message
      Logger.log e.backtrace
      Logger.log "Migration of #{course_id} failed, rolling back and deleting target course #{new_course_id}"

      if new_course_id
        ensure_db_connection
        ::Course.find(new_course_id).destroy

        new_course_id = nil
      end
      started.each(&:rollback)
    end

    new_course_id
  end

  def tables
    @tables ||= begin
      ts = []
      ts << CourseTable.new(store, course_id, fix_id: @fix_id)

      ts += [
        CourseUserTable,
        AnnouncementTable,
        AchievementTable,
        LevelTable,
        ExpRecordTable,
        LessonPlanMilestoneTable,
        LessonPlanEventTable,

        ForumTable,
        ForumTopicTable,
        ForumTopicViewTable,
        ForumPostTable,
        ForumPostVoteTable,

        AssessmentTabTable,
        AssessmentTable,
        AssessmentMcqQuestionTable,
        AssessmentMcqOptionTable,
        AssessmentTrqQuestionTable,
        AssessmentTrqKeywordSolutionTable,
        AssessmentTrqExactMatchSolutionTable,
        AssessmentScribingQuestionTable,
        AssessmentProgrammingQuestionTable,

        AssessmentSubmissionTable,
        AssessmentMcqAnswerTable,
        AssessmentMcqAnswerOptionTable,
        AssessmentTrqAnswerTable,
        AssessmentScribingAnswerTable,
        AssessmentAnswerScribbleTable,
        AssessmentProgrammingAnswerTable,

        AssessmentSkillGroupTable,
        AssessmentSkillTable,
        AssessmentQuestionSkillTable,
        CommentTopicTable,
        AssessmentCommentTable,
        AssessmentAnnotationTable,

        ConditionTable,
        AssessmentConditionTable,

        MaterialFolderTable,
        MaterialTable,
        LessonPlanEventMaterialTable,

        SurveyTable,
        SurveySectionTable,
        SurveyQuestionTable,
{'fraction_non_alphanumeric': 0.06222222222222222, 'fraction_numerical': 0.0019753086419753087, 'mean_word_length': 2.381190873678353, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3489127', 'n_tokens_mistral': 1774, 'n_tokens_neox': 1717, 'n_words': 361}