first commit
This commit is contained in:
242
internal/commands/export_import.go
Normal file
242
internal/commands/export_import.go
Normal file
@@ -0,0 +1,242 @@
|
||||
// Файл: 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)
|
||||
}
|
||||
Reference in New Issue
Block a user