243 lines
8.3 KiB
Go
243 lines
8.3 KiB
Go
// Файл: internal/commands/export_import.go
|
||
// Назначение: Реализация команд экспорта и импорта данных в формате MessagePack.
|
||
// Синтаксис: export "Имя_слайса" "название_экспортируемого_файла".msgpack
|
||
// import "Имя_слайса" "название_импортируемого_файла".msgpack
|
||
|
||
package commands
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"strings"
|
||
|
||
"futriis/internal/storage"
|
||
"futriis/pkg/utils"
|
||
"futriis/internal/serializer"
|
||
)
|
||
|
||
// ExportData экспортирует данные из слайса (базы данных) в файл MessagePack
|
||
func ExportData(store *storage.Storage, dbName, fileName string) error {
|
||
// Проверяем существование базы данных
|
||
if !store.ExistsDatabase(dbName) {
|
||
return fmt.Errorf("database '%s' not found", dbName)
|
||
}
|
||
|
||
// Получаем базу данных
|
||
db, err := store.GetDatabase(dbName)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to get database: %v", err)
|
||
}
|
||
|
||
// Собираем все данные из всех коллекций
|
||
exportData := make(map[string]interface{})
|
||
|
||
collections := db.ListCollections()
|
||
for _, collName := range collections {
|
||
coll, err := db.GetCollection(collName)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
|
||
// Получаем все документы коллекции
|
||
docs := coll.GetAllDocuments()
|
||
|
||
// Сериализуем документы в формат для экспорта
|
||
collData := make([]map[string]interface{}, 0, len(docs))
|
||
for _, doc := range docs {
|
||
docData := map[string]interface{}{
|
||
"_id": doc.ID,
|
||
"fields": doc.GetFields(),
|
||
"created_at": doc.CreatedAt,
|
||
"updated_at": doc.UpdatedAt,
|
||
"version": doc.Version,
|
||
}
|
||
collData = append(collData, docData)
|
||
}
|
||
|
||
exportData[collName] = collData
|
||
}
|
||
|
||
// Добавляем метаданные
|
||
exportData["_metadata"] = map[string]interface{}{
|
||
"database": dbName,
|
||
"export_time": fmt.Sprintf("%d", utils.GetCurrentTimestamp()),
|
||
"version": "1.0",
|
||
}
|
||
|
||
// Сериализуем в MessagePack
|
||
data, err := serializer.Marshal(exportData)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to marshal export data: %v", err)
|
||
}
|
||
|
||
// Записываем в файл
|
||
if err := os.WriteFile(fileName, data, 0644); err != nil {
|
||
return fmt.Errorf("failed to write export file: %v", err)
|
||
}
|
||
|
||
fmt.Printf("✓ Database '%s' exported successfully to %s\n", dbName, fileName)
|
||
fmt.Printf(" Collections exported: %d\n", len(collections))
|
||
|
||
return nil
|
||
}
|
||
|
||
// ImportData импортирует данные из файла MessagePack в слайс (базу данных)
|
||
func ImportData(store *storage.Storage, dbName, fileName string) error {
|
||
// Проверяем существование файла
|
||
if _, err := os.Stat(fileName); os.IsNotExist(err) {
|
||
return fmt.Errorf("import file '%s' not found", fileName)
|
||
}
|
||
|
||
// Читаем файл
|
||
data, err := os.ReadFile(fileName)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to read import file: %v", err)
|
||
}
|
||
|
||
// Десериализуем из MessagePack
|
||
var importData map[string]interface{}
|
||
if err := serializer.Unmarshal(data, &importData); err != nil {
|
||
return fmt.Errorf("failed to unmarshal import data: %v", err)
|
||
}
|
||
|
||
// Проверяем метаданные
|
||
metadata, ok := importData["_metadata"].(map[string]interface{})
|
||
if !ok {
|
||
return fmt.Errorf("invalid import file format: missing metadata")
|
||
}
|
||
|
||
sourceDB, _ := metadata["database"].(string)
|
||
fmt.Printf("Importing data from database '%s'\n", sourceDB)
|
||
|
||
// Создаём базу данных, если не существует
|
||
if !store.ExistsDatabase(dbName) {
|
||
if err := store.CreateDatabase(dbName); err != nil {
|
||
return fmt.Errorf("failed to create database: %v", err)
|
||
}
|
||
fmt.Printf("Created database '%s'\n", dbName)
|
||
}
|
||
|
||
// Получаем базу данных
|
||
db, err := store.GetDatabase(dbName)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to get database: %v", err)
|
||
}
|
||
|
||
importedCollections := 0
|
||
importedDocuments := 0
|
||
|
||
// Импортируем коллекции
|
||
for key, value := range importData {
|
||
if key == "_metadata" {
|
||
continue
|
||
}
|
||
|
||
collName := key
|
||
collData, ok := value.([]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
|
||
// Создаём коллекцию, если не существует
|
||
if _, err := db.GetCollection(collName); err != nil {
|
||
if err := db.CreateCollection(collName); err != nil {
|
||
fmt.Printf(" Warning: failed to create collection '%s': %v\n", collName, err)
|
||
continue
|
||
}
|
||
}
|
||
|
||
coll, err := db.GetCollection(collName)
|
||
if err != nil {
|
||
fmt.Printf(" Warning: failed to get collection '%s': %v\n", collName, err)
|
||
continue
|
||
}
|
||
|
||
// Импортируем документы
|
||
for _, docRaw := range collData {
|
||
docMap, ok := docRaw.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
|
||
// Создаём документ
|
||
doc := storage.NewDocument()
|
||
|
||
if id, ok := docMap["_id"].(string); ok {
|
||
doc.ID = id
|
||
}
|
||
|
||
if fields, ok := docMap["fields"].(map[string]interface{}); ok {
|
||
for k, v := range fields {
|
||
doc.SetField(k, v)
|
||
}
|
||
}
|
||
|
||
if createdAt, ok := docMap["created_at"].(int64); ok {
|
||
doc.CreatedAt = createdAt
|
||
}
|
||
|
||
if updatedAt, ok := docMap["updated_at"].(int64); ok {
|
||
doc.UpdatedAt = updatedAt
|
||
}
|
||
|
||
if version, ok := docMap["version"].(uint64); ok {
|
||
doc.Version = version
|
||
}
|
||
|
||
// Вставляем документ
|
||
if err := coll.Insert(doc); err != nil {
|
||
fmt.Printf(" Warning: failed to insert document %s: %v\n", doc.ID, err)
|
||
continue
|
||
}
|
||
|
||
importedDocuments++
|
||
}
|
||
|
||
importedCollections++
|
||
}
|
||
|
||
fmt.Printf("✓ Database '%s' imported successfully from %s\n", dbName, fileName)
|
||
fmt.Printf(" Collections imported: %d\n", importedCollections)
|
||
fmt.Printf(" Documents imported: %d\n", importedDocuments)
|
||
|
||
return nil
|
||
}
|
||
|
||
// ExecuteExport выполняет команду экспорта
|
||
func ExecuteExport(store *storage.Storage, cmd string) error {
|
||
// Формат: export "Имя_слайса" "название_экспортируемого_файла".msgpack
|
||
parts := strings.SplitN(cmd, " ", 3)
|
||
if len(parts) < 3 {
|
||
return fmt.Errorf("usage: export \"database_name\" \"filename.msgpack\"")
|
||
}
|
||
|
||
dbName := strings.Trim(parts[1], "\"")
|
||
fileName := strings.Trim(parts[2], "\"")
|
||
|
||
// Проверяем расширение файла
|
||
if !strings.HasSuffix(fileName, ".msgpack") {
|
||
fileName = fileName + ".msgpack"
|
||
}
|
||
|
||
return ExportData(store, dbName, fileName)
|
||
}
|
||
|
||
// ExecuteImport выполняет команду импорта
|
||
func ExecuteImport(store *storage.Storage, cmd string) error {
|
||
// Формат: import "Имя_слайса" "название_импортируемого_файла".msgpack
|
||
parts := strings.SplitN(cmd, " ", 3)
|
||
if len(parts) < 3 {
|
||
return fmt.Errorf("usage: import \"database_name\" \"filename.msgpack\"")
|
||
}
|
||
|
||
dbName := strings.Trim(parts[1], "\"")
|
||
fileName := strings.Trim(parts[2], "\"")
|
||
|
||
// Проверяем расширение файла
|
||
if !strings.HasSuffix(fileName, ".msgpack") {
|
||
fileName = fileName + ".msgpack"
|
||
}
|
||
|
||
return ImportData(store, dbName, fileName)
|
||
}
|