From a09f2f873bed73baa844a84361873954b214f499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=A1?= =?UTF-8?q?=D0=B0=D1=84=D1=80=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Sun, 1 Mar 2026 00:49:02 +0000 Subject: [PATCH] Delete internal/engine/engine.go --- internal/engine/engine.go | 993 -------------------------------------- 1 file changed, 993 deletions(-) delete mode 100644 internal/engine/engine.go diff --git a/internal/engine/engine.go b/internal/engine/engine.go deleted file mode 100644 index e8bc315..0000000 --- a/internal/engine/engine.go +++ /dev/null @@ -1,993 +0,0 @@ -// /futriis/internal/engine/engine.go -// Пакет engine реализует ядро СУБД Futriis, координирующее все операции. -// Выступает в роли центрального компонента, связывающего хранилище, кластерное управление, транзакции, Lua плагины и AOF (Append-Only File) для персистентности. - -package engine - -import ( - "fmt" - "reflect" - "strings" - - "futriis/internal/cluster" - "futriis/internal/lua" - "futriis/internal/replication" - "futriis/internal/storage" - "futriis/internal/transaction" - "futriis/pkg/config" - "futriis/pkg/types" - "futriis/pkg/utils" -) - -// Engine представляет ядро СУБД -type Engine struct { - storage *storage.Storage - clusterMgr *cluster.ClusterManager - txMgr *transaction.TransactionManager - luaMgr *lua.PluginManager - aofMgr *replication.AOFManager - cfg *config.Config - aofRecovered bool // Флаг, было ли восстановление из AOF -} - -// NewEngine создаёт новый экземпляр ядра СУБД -func NewEngine() *Engine { - cfg := config.Get() - - // Создаём AOF менеджер - aofMgr, _ := replication.NewAOFManager(cfg.Node.AOFFile, cfg.Node.AOFEnabled) - - // Воспроизводим AOF если нужно - aofRecovered := false - if aofMgr != nil && cfg.Node.AOFEnabled { - // Восстановление состояния из AOF - if err := replayAOF(aofMgr); err != nil { - utils.PrintError("Error recovering from AOF: %v", err) - } else { - aofRecovered = true - // Сообщение будет показано в handler.go - } - } - - return &Engine{ - storage: storage.NewStorage(), - clusterMgr: cluster.NewClusterManager(cfg), - txMgr: transaction.NewTransactionManager(), - luaMgr: lua.NewPluginManager(&cfg.Lua), - aofMgr: aofMgr, - cfg: cfg, - aofRecovered: aofRecovered, - } -} - -// GetConfig возвращает конфигурацию -func (e *Engine) GetConfig() *config.Config { - return e.cfg -} - -// WasAOFRecovered возвращает флаг восстановления из AOF -func (e *Engine) WasAOFRecovered() bool { - return e.aofRecovered -} - -// replayAOF воспроизводит команды из AOF файла для восстановления состояния -func replayAOF(aofMgr *replication.AOFManager) error { - commands, err := aofMgr.ReadAll() - if err != nil { - return fmt.Errorf("failed to read AOF: %v", err) - } - - // Создаём временное хранилище для восстановления - tempStorage := storage.NewStorage() - - for i, cmd := range commands { - // Пропускаем команды транзакций при восстановлении - if cmd.Name == "begin" || cmd.Name == "commit" || cmd.Name == "rollback" { - continue - } - - // Преобразуем аргументы в строки - args := make([]string, len(cmd.Args)) - for j, arg := range cmd.Args { - if str, ok := arg.(string); ok { - args[j] = str - } else { - args[j] = fmt.Sprint(arg) - } - } - - // Выполняем команду на временном хранилище - if err := executeRestoreCommand(tempStorage, cmd.Name, args); err != nil { - utils.PrintWarning("Error replaying command #%d (%s): %v", i+1, cmd.Name, err) - // Продолжаем восстановление, несмотря на ошибки - } - } - - // TODO: Перенести восстановленные данные в основное хранилище - // Это упрощённая реализация, в реальности нужно синхронизировать состояния - - return nil -} - -// executeRestoreCommand выполняет команду при восстановлении из AOF -func executeRestoreCommand(storage *storage.Storage, cmdName string, args []string) error { - switch cmdName { - case "create": - if len(args) < 2 { - return nil - } - switch args[0] { - case "tapple": - if len(args) < 2 { - return nil - } - _, err := storage.GetTappleManager().CreateTapple(args[1]) - return err - case "slice": - if len(args) < 3 { - return nil - } - tapple, err := storage.GetTappleManager().GetTapple(args[1]) - if err != nil { - return err - } - _, err = storage.GetTappleManager().GetSliceManager().CreateSlice(tapple, args[2]) - return err - case "tuple": - if len(args) < 4 { - return nil - } - tapple, err := storage.GetTappleManager().GetTapple(args[1]) - if err != nil { - return err - } - slice, err := storage.GetTappleManager().GetSliceManager().GetSlice(tapple, args[2]) - if err != nil { - return err - } - fields := make(map[string]interface{}) - for i := 4; i < len(args); i++ { - parts := strings.SplitN(args[i], "=", 2) - if len(parts) == 2 { - fields[parts[0]] = parts[1] - } - } - _, err = storage.GetTappleManager().GetSliceManager().GetTupleManager().CreateTuple(slice, args[3], fields) - return err - } - case "update": - if len(args) < 4 || args[0] != "tuple" { - return nil - } - tapple, err := storage.GetTappleManager().GetTapple(args[1]) - if err != nil { - return err - } - slice, err := storage.GetTappleManager().GetSliceManager().GetSlice(tapple, args[2]) - if err != nil { - return err - } - fields := make(map[string]interface{}) - for i := 4; i < len(args); i++ { - parts := strings.SplitN(args[i], "=", 2) - if len(parts) == 2 { - fields[parts[0]] = parts[1] - } - } - _, err = storage.GetTappleManager().GetSliceManager().GetTupleManager().UpdateTuple(slice, args[3], fields) - return err - case "delete": - if len(args) < 2 { - return nil - } - switch args[0] { - case "tapple": - if len(args) < 2 { - return nil - } - return storage.GetTappleManager().DeleteTapple(args[1]) - case "slice": - if len(args) < 3 { - return nil - } - tapple, err := storage.GetTappleManager().GetTapple(args[1]) - if err != nil { - return err - } - return storage.GetTappleManager().GetSliceManager().DeleteSlice(tapple, args[2]) - case "tuple": - if len(args) < 4 { - return nil - } - tapple, err := storage.GetTappleManager().GetTapple(args[1]) - if err != nil { - return err - } - slice, err := storage.GetTappleManager().GetSliceManager().GetSlice(tapple, args[2]) - if err != nil { - return err - } - return storage.GetTappleManager().GetSliceManager().GetTupleManager().DeleteTuple(slice, args[3]) - } - } - return nil -} - -// Execute выполняет команду и возвращает результат -func (e *Engine) Execute(input string) (string, error) { - // Разбираем ввод - parts := strings.Fields(input) - if len(parts) == 0 { - return "", nil - } - - command := strings.ToLower(parts[0]) - args := parts[1:] - - // Записываем команду в AOF (кроме команд транзакций и служебных команд) - if e.aofMgr != nil && command != "begin" && command != "commit" && command != "rollback" && - command != "cluster.status" && command != "help" && command != "exit" && command != "quit" && - command != "aof.recover" && command != "aof.info" && - !strings.HasPrefix(command, "add.prime.index") && !strings.HasPrefix(command, "delete.prime.index") && - !strings.HasPrefix(command, "add.secondary.index") && !strings.HasPrefix(command, "delete.secondary.index") && - command != "cluster.rebalance" { - argsInterface := make([]interface{}, len(args)) - for i, v := range args { - argsInterface[i] = v - } - e.aofMgr.Append(command, argsInterface) - } - - // Обработка команд - switch command { - case "help": - return e.help(), nil - - case "exit", "quit": - return "exit", nil - - case "create": - return e.handleCreate(args) - - case "delete": - return e.handleDelete(args) - - case "update": - return e.handleUpdate(args) - - case "list": - return e.handleList(args) - - case "show": - return e.handleShow(args) - - case "begin": - return e.handleBegin() - - case "commit": - return e.handleCommit() - - case "rollback": - return e.handleRollback() - - case "cluster.status": - return e.handleClusterStatus() - - case "cluster.rebalance": - return e.handleClusterRebalance(args) - - case "add.node": - return e.handleAddNode(args) - - case "evict.node": - return e.handleEvictNode(args) - - case "lua": - return e.handleLua(args) - - case "aof.recover": - return e.handleAOFRecover(args) - - case "aof.info": - return e.handleAOFInfo() - - case "add.prime.index": - return e.handleAddPrimaryIndex(args) - - case "delete.prime.index": - return e.handleDeletePrimaryIndex(args) - - case "add.secondary.index": - return e.handleAddSecondaryIndex(args) - - case "delete.secondary.index": - return e.handleDeleteSecondaryIndex(args) - - case "compression.stats": - return e.handleCompressionStats(args) - - case "sharding.status": - return e.handleShardingStatus() - - default: - return "", fmt.Errorf("unknown command: %s", command) - } -} - -// handleAOFRecover восстанавливает данные из AOF файла -func (e *Engine) handleAOFRecover(args []string) (string, error) { - if e.aofMgr == nil { - return "", fmt.Errorf("AOF manager not initialized") - } - - // Проверяем, указан ли путь к файлу - filePath := e.cfg.Node.AOFFile - if len(args) > 0 { - filePath = args[0] - } - - // Создаём временный AOF менеджер для чтения указанного файла - tmpAOF, err := replication.NewAOFManager(filePath, true) - if err != nil { - return "", fmt.Errorf("failed to open AOF file: %v", err) - } - defer tmpAOF.Close() - - // Читаем все команды - commands, err := tmpAOF.ReadAll() - if err != nil { - return "", fmt.Errorf("failed to read AOF file: %v", err) - } - - if len(commands) == 0 { - return utils.ColorYellow + "AOF file is empty" + utils.ColorReset, nil - } - - // Создаём временное хранилище для проверки - tempStorage := storage.NewStorage() - successCount := 0 - errorCount := 0 - - for i, cmd := range commands { - if cmd.Name == "begin" || cmd.Name == "commit" || cmd.Name == "rollback" { - continue - } - - args := make([]string, len(cmd.Args)) - for j, arg := range cmd.Args { - if str, ok := arg.(string); ok { - args[j] = str - } else { - args[j] = fmt.Sprint(arg) - } - } - - if err := executeRestoreCommand(tempStorage, cmd.Name, args); err != nil { - utils.PrintWarning("Error in command #%d: %v", i+1, err) - errorCount++ - } else { - successCount++ - } - } - - return fmt.Sprintf(utils.ColorGreen+"Recovery completed. Successful: %d, Errors: %d"+utils.ColorReset, - successCount, errorCount), nil -} - -// handleAOFInfo показывает информацию о AOF файле -func (e *Engine) handleAOFInfo() (string, error) { - if e.aofMgr == nil { - return "", fmt.Errorf("AOF manager not initialized") - } - - // Получаем информацию о файле напрямую - filePath := e.cfg.Node.AOFFile - commands, err := e.aofMgr.ReadAll() - if err != nil { - return "", fmt.Errorf("failed to read AOF file: %v", err) - } - - // Получаем размер файла - fileInfo, err := e.aofMgr.GetFileInfo() - if err != nil { - fileInfo = "unavailable" - } - - result := utils.ColorCyan + "AOF Information:" + utils.ColorReset + "\n" - result += fmt.Sprintf(" File: %s\n", filePath) - result += fmt.Sprintf(" Size: %v\n", fileInfo) - result += fmt.Sprintf(" Commands: %d\n", len(commands)) - if len(commands) > 0 { - lastCmd := commands[len(commands)-1] - result += fmt.Sprintf(" Last write: %d\n", lastCmd.Time) - } else { - result += " Last write: no records\n" - } - - return result, nil -} - -// handleClusterRebalance выполняет ребалансировку кластера -func (e *Engine) handleClusterRebalance(args []string) (string, error) { - clusterName := "futriis-cluster" - if len(args) > 0 { - clusterName = args[0] - } - - err := e.clusterMgr.RebalanceCluster() - if err != nil { - return "", fmt.Errorf("cluster rebalance failed: %v", err) - } - - return utils.ColorGreen + "Cluster '" + clusterName + "' rebalanced successfully" + utils.ColorReset, nil -} - -// handleCreate обрабатывает команды создания -func (e *Engine) handleCreate(args []string) (string, error) { - if len(args) < 2 { - return "", fmt.Errorf("insufficient arguments for create command") - } - - switch args[0] { - case "tapple": - if len(args) < 2 { - return "", fmt.Errorf("tapple name not specified") - } - return e.createTapple(args[1]) - case "slice": - if len(args) < 3 { - return "", fmt.Errorf("insufficient arguments for slice creation") - } - return e.createSlice(args[1], args[2]) - case "tuple": - if len(args) < 4 { - return "", fmt.Errorf("insufficient arguments for tuple creation") - } - return e.createTuple(args[1], args[2], args[3], args[4:]) - default: - return "", fmt.Errorf("unknown creation type: %s", args[0]) - } -} - -// handleDelete обрабатывает команды удаления -func (e *Engine) handleDelete(args []string) (string, error) { - if len(args) < 2 { - return "", fmt.Errorf("insufficient arguments for delete command") - } - - switch args[0] { - case "tapple": - if len(args) < 2 { - return "", fmt.Errorf("tapple name not specified") - } - return e.deleteTapple(args[1]) - case "slice": - if len(args) < 3 { - return "", fmt.Errorf("insufficient arguments for slice deletion") - } - return e.deleteSlice(args[1], args[2]) - case "tuple": - if len(args) < 4 { - return "", fmt.Errorf("insufficient arguments for tuple deletion") - } - return e.deleteTuple(args[1], args[2], args[3]) - default: - return "", fmt.Errorf("unknown deletion type: %s", args[0]) - } -} - -// handleUpdate обрабатывает команды обновления -func (e *Engine) handleUpdate(args []string) (string, error) { - if len(args) < 4 || args[0] != "tuple" { - return "", fmt.Errorf("invalid update command") - } - return e.updateTuple(args[1], args[2], args[3], args[4:]) -} - -// handleList обрабатывает команды списка -func (e *Engine) handleList(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("insufficient arguments for list command") - } - - switch args[0] { - case "tapples": - return e.listTapples() - case "slices": - if len(args) < 2 { - return "", fmt.Errorf("tapple name not specified") - } - return e.listSlices(args[1]) - default: - return "", fmt.Errorf("unknown list type: %s", args[0]) - } -} - -// handleShow обрабатывает команды показа -func (e *Engine) handleShow(args []string) (string, error) { - if len(args) < 2 || args[0] != "tuples" { - return "", fmt.Errorf("invalid show command") - } - if len(args) < 3 { - return "", fmt.Errorf("insufficient arguments for show tuples") - } - return e.showTuples(args[1], args[2]) -} - -// handleBegin начинает транзакцию -func (e *Engine) handleBegin() (string, error) { - id, err := e.txMgr.Begin() - if err != nil { - return "", err - } - return utils.ColorGreen + "Transaction started. ID: " + id + utils.ColorReset, nil -} - -// handleCommit фиксирует транзакцию -func (e *Engine) handleCommit() (string, error) { - err := e.txMgr.Commit() - if err != nil { - return "", err - } - return utils.ColorGreen + "Transaction committed" + utils.ColorReset, nil -} - -// handleRollback откатывает транзакцию -func (e *Engine) handleRollback() (string, error) { - err := e.txMgr.Rollback() - if err != nil { - return "", err - } - return utils.ColorGreen + "Transaction rolled back" + utils.ColorReset, nil -} - -// handleClusterStatus показывает статус кластера -func (e *Engine) handleClusterStatus() (string, error) { - status := e.clusterMgr.GetClusterStatus() - - result := utils.ColorCyan + "Cluster Status:" + utils.ColorReset + "\n" - result += fmt.Sprintf(" Total nodes: %d\n", status["total_nodes"]) - result += fmt.Sprintf(" Active nodes: %d\n", status["active_nodes"]) - result += fmt.Sprintf(" Coordinator: %v\n", status["coordinator"]) - result += fmt.Sprintf(" Master-master replication: %v\n", status["master_master"]) - - nodes, _ := status["nodes"].([]map[string]interface{}) - if len(nodes) > 0 { - result += utils.ColorCyan + "\nCluster Nodes:" + utils.ColorReset + "\n" - for _, node := range nodes { - result += fmt.Sprintf(" %s (%s) - %s, last seen: %s\n", - node["id"], node["address"], node["state"], node["last_seen"]) - } - } - - return result, nil -} - -// handleAddNode добавляет узел в кластер -func (e *Engine) handleAddNode(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("specify node address") - } - - address := args[0] - err := e.clusterMgr.AddNode(address) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Node " + address + " added to cluster" + utils.ColorReset, nil -} - -// handleEvictNode удаляет узел из кластера -func (e *Engine) handleEvictNode(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("specify node ID or address") - } - - nodeID := args[0] - err := e.clusterMgr.RemoveNode(nodeID) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Node " + nodeID + " removed from cluster" + utils.ColorReset, nil -} - -// handleLua выполняет Lua скрипт -func (e *Engine) handleLua(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("specify plugin name") - } - - pluginName := args[0] - err := e.luaMgr.ExecutePlugin(pluginName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Plugin executed" + utils.ColorReset, nil -} - -// handleAddPrimaryIndex обрабатывает создание первичного индекса -func (e *Engine) handleAddPrimaryIndex(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("specify tapple name") - } - - tappleName := args[0] - - // Получаем таппл - _, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", fmt.Errorf("tapple not found: %v", err) - } - - // Создаём первичный индекс - indexManager := e.storage.GetTappleManager().GetIndexManager() - err = indexManager.CreatePrimaryIndex(tappleName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Primary index for tapple '" + tappleName + "' created successfully" + utils.ColorReset, nil -} - -// handleDeletePrimaryIndex обрабатывает удаление первичного индекса -func (e *Engine) handleDeletePrimaryIndex(args []string) (string, error) { - if len(args) < 1 { - return "", fmt.Errorf("specify tapple name") - } - - tappleName := args[0] - - indexManager := e.storage.GetTappleManager().GetIndexManager() - err := indexManager.DeletePrimaryIndex(tappleName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Primary index for tapple '" + tappleName + "' deleted successfully" + utils.ColorReset, nil -} - -// handleAddSecondaryIndex обрабатывает создание вторичного индекса -func (e *Engine) handleAddSecondaryIndex(args []string) (string, error) { - if len(args) < 2 { - return "", fmt.Errorf("specify tapple name and field name") - } - - tappleName := args[0] - fieldName := args[1] - - // Получаем таппл - _, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", fmt.Errorf("tapple not found: %v", err) - } - - // Создаём вторичный индекс - indexManager := e.storage.GetTappleManager().GetIndexManager() - err = indexManager.CreateSecondaryIndex(tappleName, fieldName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Secondary index for tapple '" + tappleName + "' on field '" + fieldName + "' created successfully" + utils.ColorReset, nil -} - -// handleDeleteSecondaryIndex обрабатывает удаление вторичного индекса -func (e *Engine) handleDeleteSecondaryIndex(args []string) (string, error) { - if len(args) < 2 { - return "", fmt.Errorf("specify tapple name and field name") - } - - tappleName := args[0] - fieldName := args[1] - - indexManager := e.storage.GetTappleManager().GetIndexManager() - err := indexManager.DeleteSecondaryIndex(tappleName, fieldName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Secondary index for tapple '" + tappleName + "' on field '" + fieldName + "' deleted successfully" + utils.ColorReset, nil -} - -// handleCompressionStats показывает статистику сжатия -func (e *Engine) handleCompressionStats(args []string) (string, error) { - result := utils.ColorCyan + "Compression Statistics:" + utils.ColorReset + "\n" - result += " Compression statistics available at slice level\n" - result += " Use 'show compression ' for detailed information" - - return result, nil -} - -// handleShardingStatus показывает статус шардинга -func (e *Engine) handleShardingStatus() (string, error) { - status := e.clusterMgr.GetClusterStatus() - - shardingInfo, exists := status["sharding"] - if !exists { - return utils.ColorYellow + "Sharding is not activated" + utils.ColorReset, nil - } - - shardStats := shardingInfo.(map[string]interface{}) - - result := utils.ColorCyan + "Sharding Status:" + utils.ColorReset + "\n" - result += fmt.Sprintf(" Enabled: %v\n", shardStats["enabled"]) - result += fmt.Sprintf(" Strategy: %s\n", shardStats["strategy"]) - result += fmt.Sprintf(" Total shards: %d\n", shardStats["total_shards"]) - - shards, _ := shardStats["shards"].([]map[string]interface{}) - if len(shards) > 0 { - result += utils.ColorCyan + "\nShards:" + utils.ColorReset + "\n" - for _, shard := range shards { - result += fmt.Sprintf(" %s: nodes=%v, reads=%d, writes=%d\n", - shard["id"], shard["nodes"], shard["reads"], shard["writes"]) - } - } - - return result, nil -} - -// Методы для работы с тапплами -func (e *Engine) createTapple(name string) (string, error) { - tapple, err := e.storage.GetTappleManager().CreateTapple(name) - if err != nil { - return "", err - } - return utils.ColorGreen + "Tapple '" + tapple.Name + "' created successfully" + utils.ColorReset, nil -} - -func (e *Engine) deleteTapple(name string) (string, error) { - err := e.storage.GetTappleManager().DeleteTapple(name) - if err != nil { - return "", err - } - return utils.ColorGreen + "Tapple '" + name + "' deleted successfully" + utils.ColorReset, nil -} - -func (e *Engine) listTapples() (string, error) { - tapples := e.storage.GetTappleManager().ListTapples() - if len(tapples) == 0 { - return utils.ColorYellow + "No tapples found" + utils.ColorReset, nil - } - - result := utils.ColorCyan + "List of tapples:" + utils.ColorReset + "\n" - for _, t := range tapples { - result += " " + utils.ColorGreen + t + utils.ColorReset + "\n" - } - return result, nil -} - -// Методы для работы со слайсами -func (e *Engine) createSlice(tappleName, sliceName string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slice, err := e.storage.GetTappleManager().GetSliceManager().CreateSlice(tapple, sliceName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Slice '" + slice.Name + "' in tapple '" + tappleName + "' created successfully" + utils.ColorReset, nil -} - -func (e *Engine) deleteSlice(tappleName, sliceName string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - err = e.storage.GetTappleManager().GetSliceManager().DeleteSlice(tapple, sliceName) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Slice '" + sliceName + "' in tapple '" + tappleName + "' deleted successfully" + utils.ColorReset, nil -} - -func (e *Engine) listSlices(tappleName string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slices := e.storage.GetTappleManager().GetSliceManager().ListSlices(tapple) - if len(slices) == 0 { - return utils.ColorYellow + "No slices found in tapple '" + tappleName + "'" + utils.ColorReset, nil - } - - result := utils.ColorCyan + "List of slices in tapple '" + tappleName + "':" + utils.ColorReset + "\n" - for _, s := range slices { - result += " " + utils.ColorGreen + s + utils.ColorReset + "\n" - } - return result, nil -} - -// Методы для работы с кортежами -func (e *Engine) createTuple(tappleName, sliceName, tupleID string, fieldsArgs []string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slice, err := e.storage.GetTappleManager().GetSliceManager().GetSlice(tapple, sliceName) - if err != nil { - return "", err - } - - // Парсим поля - fields := make(map[string]interface{}) - for _, arg := range fieldsArgs { - parts := strings.SplitN(arg, "=", 2) - if len(parts) == 2 { - fields[parts[0]] = parts[1] - } - } - - tuple, err := e.storage.GetTappleManager().GetSliceManager().GetTupleManager().CreateTuple(slice, tupleID, fields) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Tuple '" + tuple.ID + "' in slice '" + sliceName + "' created successfully" + utils.ColorReset, nil -} - -func (e *Engine) deleteTuple(tappleName, sliceName, tupleID string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slice, err := e.storage.GetTappleManager().GetSliceManager().GetSlice(tapple, sliceName) - if err != nil { - return "", err - } - - err = e.storage.GetTappleManager().GetSliceManager().GetTupleManager().DeleteTuple(slice, tupleID) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Tuple '" + tupleID + "' in slice '" + sliceName + "' deleted successfully" + utils.ColorReset, nil -} - -func (e *Engine) updateTuple(tappleName, sliceName, tupleID string, fieldsArgs []string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slice, err := e.storage.GetTappleManager().GetSliceManager().GetSlice(tapple, sliceName) - if err != nil { - return "", err - } - - // Парсим поля - fields := make(map[string]interface{}) - for _, arg := range fieldsArgs { - parts := strings.SplitN(arg, "=", 2) - if len(parts) == 2 { - fields[parts[0]] = parts[1] - } - } - - tuple, err := e.storage.GetTappleManager().GetSliceManager().GetTupleManager().UpdateTuple(slice, tupleID, fields) - if err != nil { - return "", err - } - - return utils.ColorGreen + "Tuple '" + tuple.ID + "' in slice '" + sliceName + "' updated successfully" + utils.ColorReset, nil -} - -// showTuples показывает все кортежи в слайсе -func (e *Engine) showTuples(tappleName, sliceName string) (string, error) { - tapple, err := e.storage.GetTappleManager().GetTapple(tappleName) - if err != nil { - return "", err - } - - slice, err := e.storage.GetTappleManager().GetSliceManager().GetSlice(tapple, sliceName) - if err != nil { - return "", err - } - - // Получаем все кортежи из слайса через рефлексию - tuples, err := e.getAllTuplesFromSlice(slice) - if err != nil { - return "", err - } - - if len(tuples) == 0 { - return utils.ColorYellow + "No tuples found in slice '" + sliceName + "'" + utils.ColorReset, nil - } - - result := utils.ColorCyan + "List of tuples in slice '" + sliceName + "':" + utils.ColorReset + "\n" - for id, tuple := range tuples { - result += " " + utils.ColorGreen + "ID: " + id + utils.ColorReset + "\n" - for k, v := range tuple.Fields { - result += " " + utils.ColorYellow + k + utils.ColorReset + ": " + utils.ColorPromptCode + fmt.Sprint(v) + utils.ColorReset + "\n" - } - result += "\n" - } - return result, nil -} - -// вспомогательная функция для получения всех кортежей из слайса через рефлексию -func (e *Engine) getAllTuplesFromSlice(slice *types.Slice) (map[string]*types.Tuple, error) { - if slice == nil { - return nil, fmt.Errorf("slice is nil") - } - - // Используем рефлексию для доступа к неэкспортируемому полю tuples - v := reflect.ValueOf(slice).Elem() - field := v.FieldByName("tuples") - - if !field.IsValid() || field.Kind() != reflect.Map { - return nil, fmt.Errorf("cannot access tuples field in slice") - } - - result := make(map[string]*types.Tuple) - iter := field.MapRange() - for iter.Next() { - key := iter.Key().String() - value := iter.Value().Interface() - if tuple, ok := value.(*types.Tuple); ok { - result[key] = tuple - } - } - - return result, nil -} - -// help возвращает справку по командам -func (e *Engine) help() string { - help := utils.ColorCyan + "Available commands:" + utils.ColorReset + "\n" - - help += "\n" + utils.ColorYellow + "Basic commands:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "create tapple " + utils.ColorReset + " - create a new tapple (database)\n" - help += " " + utils.ColorGreen + "create slice " + utils.ColorReset + " - create a new slice (table)\n" - help += " " + utils.ColorGreen + "create tuple [key=value...]" + utils.ColorReset + " - create a new tuple (record)\n" - help += " " + utils.ColorGreen + "delete tapple " + utils.ColorReset + " - delete a tapple\n" - help += " " + utils.ColorGreen + "delete slice " + utils.ColorReset + " - delete a slice\n" - help += " " + utils.ColorGreen + "delete tuple " + utils.ColorReset + " - delete a tuple\n" - help += " " + utils.ColorGreen + "update tuple [key=value...]" + utils.ColorReset + " - update a tuple\n" - help += " " + utils.ColorGreen + "list tapples" + utils.ColorReset + " - show all tapples\n" - help += " " + utils.ColorGreen + "list slices " + utils.ColorReset + " - show all slices in a tapple\n" - help += " " + utils.ColorGreen + "show tuples " + utils.ColorReset + " - show all tuples in a slice\n" - - help += "\n" + utils.ColorYellow + "Index management:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "add.prime.index " + utils.ColorReset + " - create primary index for tapple\n" - help += " " + utils.ColorGreen + "delete.prime.index " + utils.ColorReset + " - delete primary index\n" - help += " " + utils.ColorGreen + "add.secondary.index " + utils.ColorReset + " - create secondary index on field\n" - help += " " + utils.ColorGreen + "delete.secondary.index " + utils.ColorReset + " - delete secondary index\n" - - help += "\n" + utils.ColorYellow + "Transactions:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "begin" + utils.ColorReset + " - start a transaction\n" - help += " " + utils.ColorGreen + "commit" + utils.ColorReset + " - commit a transaction\n" - help += " " + utils.ColorGreen + "rollback" + utils.ColorReset + " - rollback a transaction\n" - - help += "\n" + utils.ColorYellow + "Cluster and sharding management:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "cluster.status" + utils.ColorReset + " - show cluster status\n" - help += " " + utils.ColorGreen + "cluster.rebalance [cluster_name]" + utils.ColorReset + " - rebalance the cluster\n" - help += " " + utils.ColorGreen + "sharding.status" + utils.ColorReset + " - show sharding status\n" - help += " " + utils.ColorGreen + "add.node
" + utils.ColorReset + " - add a node to the cluster\n" - help += " " + utils.ColorGreen + "evict.node " + utils.ColorReset + " - remove a node from the cluster\n" - - help += "\n" + utils.ColorYellow + "Compression:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "compression.stats" + utils.ColorReset + " - show compression statistics\n" - - help += "\n" + utils.ColorYellow + "AOF management:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "aof.recover [file]" + utils.ColorReset + " - recover data from AOF file\n" - help += " " + utils.ColorGreen + "aof.info" + utils.ColorReset + " - show AOF file information\n" - - help += "\n" + utils.ColorYellow + "Lua plugins:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "lua " + utils.ColorReset + " - execute Lua plugin\n" - - help += "\n" + utils.ColorYellow + "Other:" + utils.ColorReset + "\n" - help += " " + utils.ColorGreen + "exit/quit" + utils.ColorReset + " - exit the DBMS\n" - - return help -}