waveterm/pkg/wstore/wstore.go

251 lines
7.3 KiB
Go
Raw Normal View History

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package wstore
import (
2024-05-22 06:15:11 +02:00
"context"
2024-05-21 20:09:22 +02:00
"fmt"
2024-05-21 20:09:22 +02:00
"github.com/google/uuid"
2024-09-05 23:25:45 +02:00
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
"github.com/wavetermdev/waveterm/pkg/waveobj"
)
2024-05-26 20:59:14 +02:00
func init() {
2024-08-20 23:56:48 +02:00
for _, rtype := range waveobj.AllWaveObjTypes() {
2024-05-27 08:05:11 +02:00
waveobj.RegisterType(rtype)
}
2024-05-26 20:59:14 +02:00
}
2024-08-20 23:56:48 +02:00
func CreateTab(ctx context.Context, workspaceId string, name string) (*waveobj.Tab, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (*waveobj.Tab, error) {
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
if ws == nil {
return nil, fmt.Errorf("workspace not found: %q", workspaceId)
}
layoutStateId := uuid.NewString()
2024-08-20 23:56:48 +02:00
tab := &waveobj.Tab{
OID: uuid.NewString(),
Name: name,
BlockIds: []string{},
LayoutState: layoutStateId,
}
2024-08-20 23:56:48 +02:00
layoutState := &waveobj.LayoutState{
OID: layoutStateId,
}
ws.TabIds = append(ws.TabIds, tab.OID)
DBInsert(tx.Context(), tab)
DBInsert(tx.Context(), layoutState)
DBUpdate(tx.Context(), ws)
return tab, nil
})
2024-05-21 20:09:22 +02:00
}
2024-08-20 23:56:48 +02:00
func CreateWorkspace(ctx context.Context) (*waveobj.Workspace, error) {
ws := &waveobj.Workspace{
OID: uuid.NewString(),
2024-05-26 20:59:14 +02:00
TabIds: []string{},
2024-05-21 20:09:22 +02:00
}
DBInsert(ctx, ws)
2024-05-21 20:09:22 +02:00
return ws, nil
}
2024-05-22 06:15:11 +02:00
2024-06-18 06:50:33 +02:00
func UpdateWorkspaceTabIds(ctx context.Context, workspaceId string, tabIds []string) error {
return WithTx(ctx, func(tx *TxWrap) error {
2024-08-20 23:56:48 +02:00
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
2024-06-18 06:50:33 +02:00
if ws == nil {
return fmt.Errorf("workspace not found: %q", workspaceId)
}
ws.TabIds = tabIds
DBUpdate(tx.Context(), ws)
return nil
})
}
func SetActiveTab(ctx context.Context, windowId string, tabId string) error {
return WithTx(ctx, func(tx *TxWrap) error {
2024-08-20 23:56:48 +02:00
window, _ := DBGet[*waveobj.Window](tx.Context(), windowId)
if window == nil {
return fmt.Errorf("window not found: %q", windowId)
}
2024-05-28 01:33:31 +02:00
if tabId != "" {
2024-08-20 23:56:48 +02:00
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
2024-05-28 01:33:31 +02:00
if tab == nil {
return fmt.Errorf("tab not found: %q", tabId)
}
}
window.ActiveTabId = tabId
DBUpdate(tx.Context(), window)
return nil
})
2024-05-27 08:05:11 +02:00
}
2024-06-21 19:23:04 +02:00
func UpdateTabName(ctx context.Context, tabId, name string) error {
return WithTx(ctx, func(tx *TxWrap) error {
2024-08-20 23:56:48 +02:00
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
2024-06-21 19:23:04 +02:00
if tab == nil {
return fmt.Errorf("tab not found: %q", tabId)
}
if tabId != "" {
tab.Name = name
DBUpdate(tx.Context(), tab)
}
return nil
})
}
2024-10-24 07:47:29 +02:00
func CreateSubBlock(ctx context.Context, parentBlockId string, blockDef *waveobj.BlockDef) (*waveobj.Block, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (*waveobj.Block, error) {
parentBlock, _ := DBGet[*waveobj.Block](tx.Context(), parentBlockId)
if parentBlock == nil {
return nil, fmt.Errorf("parent block not found: %q", parentBlockId)
}
blockId := uuid.NewString()
blockData := &waveobj.Block{
OID: blockId,
ParentORef: waveobj.MakeORef(waveobj.OType_Block, parentBlockId).String(),
BlockDef: blockDef,
RuntimeOpts: nil,
Meta: blockDef.Meta,
}
DBInsert(tx.Context(), blockData)
parentBlock.SubBlockIds = append(parentBlock.SubBlockIds, blockId)
DBUpdate(tx.Context(), parentBlock)
return blockData, nil
})
}
2024-08-20 23:56:48 +02:00
func CreateBlock(ctx context.Context, tabId string, blockDef *waveobj.BlockDef, rtOpts *waveobj.RuntimeOpts) (*waveobj.Block, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (*waveobj.Block, error) {
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
if tab == nil {
return nil, fmt.Errorf("tab not found: %q", tabId)
}
blockId := uuid.NewString()
2024-08-20 23:56:48 +02:00
blockData := &waveobj.Block{
OID: blockId,
2024-10-24 07:47:29 +02:00
ParentORef: waveobj.MakeORef(waveobj.OType_Tab, tabId).String(),
BlockDef: blockDef,
RuntimeOpts: rtOpts,
Meta: blockDef.Meta,
}
DBInsert(tx.Context(), blockData)
tab.BlockIds = append(tab.BlockIds, blockId)
DBUpdate(tx.Context(), tab)
return blockData, nil
})
}
2024-05-28 01:33:31 +02:00
func findStringInSlice(slice []string, val string) int {
for idx, v := range slice {
if v == val {
return idx
}
}
return -1
}
2024-10-24 07:47:29 +02:00
func DeleteBlock(ctx context.Context, blockId string) error {
2024-05-28 01:33:31 +02:00
return WithTx(ctx, func(tx *TxWrap) error {
2024-10-24 07:47:29 +02:00
block, err := DBGet[*waveobj.Block](tx.Context(), blockId)
if err != nil {
return fmt.Errorf("error getting block: %w", err)
2024-05-28 01:33:31 +02:00
}
2024-10-24 07:47:29 +02:00
if block == nil {
2024-05-28 01:33:31 +02:00
return nil
}
2024-10-24 07:47:29 +02:00
if len(block.SubBlockIds) > 0 {
return fmt.Errorf("block has subblocks, must delete subblocks first")
}
parentORef := waveobj.ParseORefNoErr(block.ParentORef)
if parentORef != nil {
if parentORef.OType == waveobj.OType_Tab {
tab, _ := DBGet[*waveobj.Tab](tx.Context(), parentORef.OID)
if tab != nil {
tab.BlockIds = utilfn.RemoveElemFromSlice(tab.BlockIds, blockId)
DBUpdate(tx.Context(), tab)
}
} else if parentORef.OType == waveobj.OType_Block {
parentBlock, _ := DBGet[*waveobj.Block](tx.Context(), parentORef.OID)
if parentBlock != nil {
parentBlock.SubBlockIds = utilfn.RemoveElemFromSlice(parentBlock.SubBlockIds, blockId)
DBUpdate(tx.Context(), parentBlock)
}
}
}
2024-08-20 23:56:48 +02:00
DBDelete(tx.Context(), waveobj.OType_Block, blockId)
2024-05-28 01:33:31 +02:00
return nil
})
}
2024-08-20 23:56:48 +02:00
// must delete all blocks individually first
// also deletes LayoutState
2024-06-20 04:10:53 +02:00
func DeleteTab(ctx context.Context, workspaceId string, tabId string) error {
2024-05-28 01:33:31 +02:00
return WithTx(ctx, func(tx *TxWrap) error {
2024-08-20 23:56:48 +02:00
tab, _ := DBGet[*waveobj.Tab](tx.Context(), tabId)
2024-05-28 01:33:31 +02:00
if tab == nil {
2024-10-24 07:47:29 +02:00
return nil
2024-05-28 01:33:31 +02:00
}
2024-08-20 23:56:48 +02:00
if len(tab.BlockIds) != 0 {
return fmt.Errorf("tab has blocks, must delete blocks first")
}
2024-10-24 07:47:29 +02:00
ws, _ := DBGet[*waveobj.Workspace](tx.Context(), workspaceId)
if ws != nil {
ws.TabIds = utilfn.RemoveElemFromSlice(ws.TabIds, tabId)
DBUpdate(tx.Context(), ws)
2024-05-28 01:33:31 +02:00
}
2024-08-20 23:56:48 +02:00
DBDelete(tx.Context(), waveobj.OType_Tab, tabId)
DBDelete(tx.Context(), waveobj.OType_LayoutState, tab.LayoutState)
2024-05-28 01:33:31 +02:00
return nil
})
}
2024-08-20 23:56:48 +02:00
func UpdateObjectMeta(ctx context.Context, oref waveobj.ORef, meta waveobj.MetaMapType) error {
return WithTx(ctx, func(tx *TxWrap) error {
if oref.IsEmpty() {
return fmt.Errorf("empty object reference")
}
obj, _ := DBGetORef(tx.Context(), oref)
if obj == nil {
return ErrNotFound
}
objMeta := waveobj.GetMeta(obj)
if objMeta == nil {
objMeta = make(map[string]any)
}
2024-08-28 03:49:49 +02:00
newMeta := waveobj.MergeMeta(objMeta, meta, false)
waveobj.SetMeta(obj, newMeta)
DBUpdate(tx.Context(), obj)
return nil
})
}
func MoveBlockToTab(ctx context.Context, currentTabId string, newTabId string, blockId string) error {
return WithTx(ctx, func(tx *TxWrap) error {
2024-10-24 07:47:29 +02:00
block, _ := DBGet[*waveobj.Block](tx.Context(), blockId)
if block == nil {
return fmt.Errorf("block not found: %q", blockId)
}
2024-08-20 23:56:48 +02:00
currentTab, _ := DBGet[*waveobj.Tab](tx.Context(), currentTabId)
if currentTab == nil {
return fmt.Errorf("current tab not found: %q", currentTabId)
}
2024-08-20 23:56:48 +02:00
newTab, _ := DBGet[*waveobj.Tab](tx.Context(), newTabId)
if newTab == nil {
return fmt.Errorf("new tab not found: %q", newTabId)
}
blockIdx := findStringInSlice(currentTab.BlockIds, blockId)
if blockIdx == -1 {
return fmt.Errorf("block not found in current tab: %q", blockId)
}
currentTab.BlockIds = utilfn.RemoveElemFromSlice(currentTab.BlockIds, blockId)
newTab.BlockIds = append(newTab.BlockIds, blockId)
2024-10-24 07:47:29 +02:00
block.ParentORef = waveobj.MakeORef(waveobj.OType_Tab, newTabId).String()
DBUpdate(tx.Context(), block)
DBUpdate(tx.Context(), currentTab)
DBUpdate(tx.Context(), newTab)
return nil
})
}