| 182 | } |
| 183 | |
| 184 | func importTable(ctx context.Context, db *gorm.DB, table any, r io.Reader) error { |
| 185 | err := db.WithContext(ctx).Migrator().DropTable(table) |
| 186 | if err != nil { |
| 187 | return errors.Wrap(err, "drop table") |
| 188 | } |
| 189 | |
| 190 | err = db.WithContext(ctx).Migrator().AutoMigrate(table) |
| 191 | if err != nil { |
| 192 | return errors.Wrap(err, "auto migrate") |
| 193 | } |
| 194 | |
| 195 | s, err := schema.Parse(table, &sync.Map{}, db.NamingStrategy) |
| 196 | if err != nil { |
| 197 | return errors.Wrap(err, "parse schema") |
| 198 | } |
| 199 | rawTableName := s.Table |
| 200 | skipResetIDSeq := map[string]bool{ |
| 201 | "lfs_object": true, |
| 202 | } |
| 203 | |
| 204 | scanner := bufio.NewScanner(r) |
| 205 | for scanner.Scan() { |
| 206 | // PostgreSQL does not like the null characters (U+0000) |
| 207 | cleaned := bytes.ReplaceAll(scanner.Bytes(), []byte("\\u0000"), []byte("")) |
| 208 | |
| 209 | elem := reflect.New(reflect.TypeOf(table).Elem()).Interface() |
| 210 | err = jsoniter.Unmarshal(cleaned, elem) |
| 211 | if err != nil { |
| 212 | return errors.Wrap(err, "unmarshal JSON to struct") |
| 213 | } |
| 214 | |
| 215 | err = db.WithContext(ctx).Create(elem).Error |
| 216 | if err != nil { |
| 217 | return errors.Wrap(err, "create row") |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | // PostgreSQL needs manually reset table sequence for auto increment keys |
| 222 | if conf.UsePostgreSQL && !skipResetIDSeq[rawTableName] { |
| 223 | seqName := rawTableName + "_id_seq" |
| 224 | if err = db.WithContext(ctx).Exec(fmt.Sprintf(`SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM "%s"), 1), false)`, seqName, rawTableName)).Error; err != nil { |
| 225 | return errors.Wrapf(err, "reset table %q.%q", rawTableName, seqName) |
| 226 | } |
| 227 | } |
| 228 | return nil |
| 229 | } |
| 230 | |
| 231 | func importLegacyTables(ctx context.Context, dirPath string, verbose bool) error { |
| 232 | snakeMapper := core.SnakeMapper{} |