waveterm/pkg/wstore/wstore_dbops.go

216 lines
6.0 KiB
Go
Raw Normal View History

2024-05-22 06:15:11 +02:00
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package wstore
import (
"context"
"fmt"
2024-05-26 20:59:14 +02:00
"github.com/wavetermdev/thenextwave/pkg/waveobj"
2024-06-12 02:42:10 +02:00
"github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil"
2024-05-26 20:59:14 +02:00
)
var ErrNotFound = fmt.Errorf("not found")
2024-05-26 20:59:14 +02:00
func waveObjTableName(w waveobj.WaveObj) string {
return "db_" + w.GetOType()
}
2024-05-27 08:05:11 +02:00
func tableNameFromOType(otype string) string {
return "db_" + otype
}
2024-05-26 20:59:14 +02:00
func tableNameGen[T waveobj.WaveObj]() string {
var zeroObj T
2024-05-27 08:05:11 +02:00
return tableNameFromOType(zeroObj.GetOType())
}
func getOTypeGen[T waveobj.WaveObj]() string {
var zeroObj T
return zeroObj.GetOType()
}
2024-05-26 20:59:14 +02:00
func DBGetCount[T waveobj.WaveObj](ctx context.Context) (int, error) {
2024-05-22 06:15:11 +02:00
return WithTxRtn(ctx, func(tx *TxWrap) (int, error) {
2024-05-26 20:59:14 +02:00
table := tableNameGen[T]()
query := fmt.Sprintf("SELECT count(*) FROM %s", table)
2024-05-22 06:15:11 +02:00
return tx.GetInt(query), nil
})
}
2024-05-26 20:59:14 +02:00
type idDataType struct {
OId string
Version int
Data []byte
2024-05-22 06:15:11 +02:00
}
2024-05-27 08:05:11 +02:00
func genericCastWithErr[T any](v any, err error) (T, error) {
if err != nil {
var zeroVal T
return zeroVal, err
}
return v.(T), err
}
2024-05-26 20:59:14 +02:00
func DBGetSingleton[T waveobj.WaveObj](ctx context.Context) (T, error) {
2024-05-27 08:05:11 +02:00
rtn, err := DBGetSingletonByType(ctx, getOTypeGen[T]())
return genericCastWithErr[T](rtn, err)
}
func DBGetSingletonByType(ctx context.Context, otype string) (waveobj.WaveObj, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (waveobj.WaveObj, error) {
table := tableNameFromOType(otype)
2024-05-26 20:59:14 +02:00
query := fmt.Sprintf("SELECT oid, version, data FROM %s LIMIT 1", table)
var row idDataType
tx.Get(&row, query)
2024-05-27 08:05:11 +02:00
rtn, err := waveobj.FromJson(row.Data)
2024-05-26 20:59:14 +02:00
if err != nil {
return rtn, err
}
2024-05-26 20:59:14 +02:00
waveobj.SetVersion(rtn, row.Version)
return rtn, nil
})
}
func DBExistsORef(ctx context.Context, oref waveobj.ORef) (bool, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (bool, error) {
table := tableNameFromOType(oref.OType)
query := fmt.Sprintf("SELECT oid FROM %s WHERE oid = ?", table)
return tx.Exists(query, oref.OID), nil
2024-05-22 06:15:11 +02:00
})
}
2024-05-26 20:59:14 +02:00
func DBGet[T waveobj.WaveObj](ctx context.Context, id string) (T, error) {
2024-05-27 08:05:11 +02:00
rtn, err := DBGetORef(ctx, waveobj.ORef{OType: getOTypeGen[T](), OID: id})
return genericCastWithErr[T](rtn, err)
}
func DBMustGet[T waveobj.WaveObj](ctx context.Context, id string) (T, error) {
rtn, err := DBGetORef(ctx, waveobj.ORef{OType: getOTypeGen[T](), OID: id})
if err != nil {
var zeroVal T
return zeroVal, err
}
if rtn == nil {
var zeroVal T
return zeroVal, ErrNotFound
}
return rtn.(T), nil
}
2024-05-27 08:05:11 +02:00
func DBGetORef(ctx context.Context, oref waveobj.ORef) (waveobj.WaveObj, error) {
return WithTxRtn(ctx, func(tx *TxWrap) (waveobj.WaveObj, error) {
table := tableNameFromOType(oref.OType)
2024-05-26 20:59:14 +02:00
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid = ?", table)
var row idDataType
2024-06-03 22:43:50 +02:00
found := tx.Get(&row, query, oref.OID)
if !found {
return nil, nil
}
2024-05-27 08:05:11 +02:00
rtn, err := waveobj.FromJson(row.Data)
2024-05-26 20:59:14 +02:00
if err != nil {
return rtn, err
}
waveobj.SetVersion(rtn, row.Version)
return rtn, nil
})
2024-05-22 06:15:11 +02:00
}
2024-05-27 08:05:11 +02:00
func dbSelectOIDs(ctx context.Context, otype string, oids []string) ([]waveobj.WaveObj, error) {
return WithTxRtn(ctx, func(tx *TxWrap) ([]waveobj.WaveObj, error) {
table := tableNameFromOType(otype)
2024-05-26 20:59:14 +02:00
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid IN (SELECT value FROM json_each(?))", table)
2024-05-27 08:05:11 +02:00
var rows []idDataType
2024-06-12 02:42:10 +02:00
tx.Select(&rows, query, dbutil.QuickJson(oids))
2024-05-27 08:05:11 +02:00
rtn := make([]waveobj.WaveObj, 0, len(rows))
for _, row := range rows {
2024-05-27 08:05:11 +02:00
waveObj, err := waveobj.FromJson(row.Data)
2024-05-26 20:59:14 +02:00
if err != nil {
return nil, err
}
2024-05-26 20:59:14 +02:00
waveobj.SetVersion(waveObj, row.Version)
2024-05-27 08:05:11 +02:00
rtn = append(rtn, waveObj)
}
return rtn, nil
})
}
func DBSelectORefs(ctx context.Context, orefs []waveobj.ORef) ([]waveobj.WaveObj, error) {
oidsByType := make(map[string][]string)
for _, oref := range orefs {
oidsByType[oref.OType] = append(oidsByType[oref.OType], oref.OID)
}
return WithTxRtn(ctx, func(tx *TxWrap) ([]waveobj.WaveObj, error) {
rtn := make([]waveobj.WaveObj, 0, len(orefs))
for otype, oids := range oidsByType {
rtnArr, err := dbSelectOIDs(tx.Context(), otype, oids)
if err != nil {
return nil, err
}
rtn = append(rtn, rtnArr...)
2024-05-22 06:15:11 +02:00
}
2024-05-27 08:05:11 +02:00
return rtn, nil
2024-05-22 06:15:11 +02:00
})
}
2024-05-27 08:05:11 +02:00
func DBSelectMap[T waveobj.WaveObj](ctx context.Context, ids []string) (map[string]T, error) {
rtnArr, err := dbSelectOIDs(ctx, getOTypeGen[T](), ids)
if err != nil {
return nil, err
}
rtnMap := make(map[string]T)
for _, obj := range rtnArr {
rtnMap[waveobj.GetOID(obj)] = obj.(T)
}
return rtnMap, nil
}
func DBDelete(ctx context.Context, otype string, id string) error {
2024-05-22 06:15:11 +02:00
return WithTx(ctx, func(tx *TxWrap) error {
2024-05-27 08:05:11 +02:00
table := tableNameFromOType(otype)
2024-05-26 20:59:14 +02:00
query := fmt.Sprintf("DELETE FROM %s WHERE oid = ?", table)
tx.Exec(query, id)
ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Delete, OType: otype, OID: id})
return nil
2024-05-22 06:15:11 +02:00
})
}
2024-05-26 20:59:14 +02:00
func DBUpdate(ctx context.Context, val waveobj.WaveObj) error {
oid := waveobj.GetOID(val)
if oid == "" {
return fmt.Errorf("cannot update %T value with empty id", val)
}
2024-05-26 20:59:14 +02:00
jsonData, err := waveobj.ToJson(val)
if err != nil {
return err
}
2024-05-22 06:15:11 +02:00
return WithTx(ctx, func(tx *TxWrap) error {
2024-05-26 20:59:14 +02:00
table := waveObjTableName(val)
query := fmt.Sprintf("UPDATE %s SET data = ?, version = version+1 WHERE oid = ? RETURNING version", table)
newVersion := tx.GetInt(query, jsonData, oid)
waveobj.SetVersion(val, newVersion)
ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Update, OType: val.GetOType(), OID: oid, Obj: val})
2024-05-22 06:15:11 +02:00
return nil
})
}
2024-05-27 08:05:11 +02:00
func DBInsert(ctx context.Context, val waveobj.WaveObj) error {
2024-05-26 20:59:14 +02:00
oid := waveobj.GetOID(val)
if oid == "" {
return fmt.Errorf("cannot insert %T value with empty id", val)
2024-05-22 06:15:11 +02:00
}
2024-05-26 20:59:14 +02:00
jsonData, err := waveobj.ToJson(val)
if err != nil {
return err
}
2024-05-22 06:15:11 +02:00
return WithTx(ctx, func(tx *TxWrap) error {
2024-05-26 20:59:14 +02:00
table := waveObjTableName(val)
waveobj.SetVersion(val, 1)
2024-05-26 20:59:14 +02:00
query := fmt.Sprintf("INSERT INTO %s (oid, version, data) VALUES (?, ?, ?)", table)
tx.Exec(query, oid, 1, jsonData)
ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Update, OType: val.GetOType(), OID: oid, Obj: val})
2024-05-22 06:15:11 +02:00
return nil
})
}