mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-03-11 13:23:06 +01:00
checkpoint on new objectservice
This commit is contained in:
parent
b1aaba2a37
commit
95ce1cc86d
26
cmd/generate/main-generate.go
Normal file
26
cmd/generate/main-generate.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
tsTypesMap := make(map[reflect.Type]string)
|
||||||
|
var waveObj waveobj.WaveObj
|
||||||
|
waveobj.GenerateTSType(reflect.TypeOf(waveobj.ORef{}), tsTypesMap)
|
||||||
|
waveobj.GenerateTSType(reflect.TypeOf(&waveObj).Elem(), tsTypesMap)
|
||||||
|
for _, rtype := range wstore.AllWaveObjTypes() {
|
||||||
|
waveobj.GenerateTSType(rtype, tsTypesMap)
|
||||||
|
}
|
||||||
|
for _, ts := range tsTypesMap {
|
||||||
|
fmt.Print(ts)
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
import { atomFamily } from "jotai/utils";
|
import * as jotaiUtils from "jotai/utils";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import * as rxjs from "rxjs";
|
import * as rxjs from "rxjs";
|
||||||
import type { WailsEvent } from "@wailsio/runtime/types/events";
|
import type { WailsEvent } from "@wailsio/runtime/types/events";
|
||||||
import { Events } from "@wailsio/runtime";
|
import { Events } from "@wailsio/runtime";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { BlockService } from "@/bindings/blockservice";
|
import { BlockService } from "@/bindings/blockservice";
|
||||||
|
import { ObjectService } from "@/bindings/objectservice";
|
||||||
import * as wstore from "@/gopkg/wstore";
|
import * as wstore from "@/gopkg/wstore";
|
||||||
|
import { Call as $Call } from "@wailsio/runtime";
|
||||||
|
|
||||||
const globalStore = jotai.createStore();
|
const globalStore = jotai.createStore();
|
||||||
|
|
||||||
@ -105,4 +108,93 @@ function removeBlockFromTab(tabId: string, blockId: string) {
|
|||||||
BlockService.CloseBlock(blockId);
|
BlockService.CloseBlock(blockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { globalStore, atoms, getBlockSubject, addBlockIdToTab, blockDataMap, useBlockAtom, removeBlockFromTab };
|
function GetObject(oref: string): Promise<any> {
|
||||||
|
let prtn = $Call.ByName(
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/service/objectservice.ObjectService.GetObject",
|
||||||
|
oref
|
||||||
|
);
|
||||||
|
return prtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaveObjectHookData = {
|
||||||
|
oref: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type WaveObjectValue<T> = {
|
||||||
|
pendingPromise: Promise<any>;
|
||||||
|
value: T;
|
||||||
|
loading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const waveObjectValueCache = new Map<string, WaveObjectValue<any>>();
|
||||||
|
let waveObjectAtomCache = new WeakMap<WaveObjectHookData, jotai.Atom<any>>();
|
||||||
|
|
||||||
|
function clearWaveObjectCache() {
|
||||||
|
waveObjectValueCache.clear();
|
||||||
|
waveObjectAtomCache = new WeakMap<WaveObjectHookData, jotai.Atom<any>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWaveObjectAtom<T>(oref: string): jotai.Atom<[T, boolean]> {
|
||||||
|
let cacheVal: WaveObjectValue<T> = waveObjectValueCache.get(oref);
|
||||||
|
if (cacheVal == null) {
|
||||||
|
cacheVal = { pendingPromise: null, value: null, loading: true };
|
||||||
|
cacheVal.pendingPromise = GetObject(oref).then((val) => {
|
||||||
|
cacheVal.value = val;
|
||||||
|
cacheVal.loading = false;
|
||||||
|
cacheVal.pendingPromise = null;
|
||||||
|
});
|
||||||
|
waveObjectValueCache.set(oref, cacheVal);
|
||||||
|
}
|
||||||
|
return jotai.atom(
|
||||||
|
(get) => {
|
||||||
|
return [cacheVal.value, cacheVal.loading];
|
||||||
|
},
|
||||||
|
(get, set, newVal: T) => {
|
||||||
|
cacheVal.value = newVal;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useWaveObjectValue<T>(oref: string): [T, boolean] {
|
||||||
|
const objRef = React.useRef<WaveObjectHookData>(null);
|
||||||
|
if (objRef.current == null) {
|
||||||
|
objRef.current = { oref: oref };
|
||||||
|
}
|
||||||
|
const objHookData = objRef.current;
|
||||||
|
let objAtom = waveObjectAtomCache.get(objHookData);
|
||||||
|
if (objAtom == null) {
|
||||||
|
objAtom = createWaveObjectAtom(oref);
|
||||||
|
waveObjectAtomCache.set(objHookData, objAtom);
|
||||||
|
}
|
||||||
|
const atomVal = jotai.useAtomValue(objAtom);
|
||||||
|
return [atomVal[0], atomVal[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
function useWaveObject<T>(oref: string): [T, boolean, (T) => void] {
|
||||||
|
const objRef = React.useRef<WaveObjectHookData>(null);
|
||||||
|
if (objRef.current == null) {
|
||||||
|
objRef.current = { oref: oref };
|
||||||
|
}
|
||||||
|
const objHookData = objRef.current;
|
||||||
|
let objAtom = waveObjectAtomCache.get(objHookData);
|
||||||
|
if (objAtom == null) {
|
||||||
|
objAtom = createWaveObjectAtom(oref);
|
||||||
|
waveObjectAtomCache.set(objHookData, objAtom);
|
||||||
|
}
|
||||||
|
const [atomVal, setAtomVal] = jotai.useAtom(objAtom);
|
||||||
|
return [atomVal[0], atomVal[1], setAtomVal];
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
globalStore,
|
||||||
|
atoms,
|
||||||
|
getBlockSubject,
|
||||||
|
addBlockIdToTab,
|
||||||
|
blockDataMap,
|
||||||
|
useBlockAtom,
|
||||||
|
removeBlockFromTab,
|
||||||
|
GetObject,
|
||||||
|
useWaveObject,
|
||||||
|
useWaveObjectValue,
|
||||||
|
clearWaveObjectCache,
|
||||||
|
};
|
||||||
|
93
frontend/types/custom.d.ts
vendored
93
frontend/types/custom.d.ts
vendored
@ -1,6 +1,97 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
declare global {}
|
declare global {
|
||||||
|
type ORef = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Block = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
version: number;
|
||||||
|
blockdef: BlockDef;
|
||||||
|
controller: string;
|
||||||
|
view: string;
|
||||||
|
meta?: { [key: string]: any };
|
||||||
|
runtimeopts?: RuntimeOpts;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BlockDef = {
|
||||||
|
controller: string;
|
||||||
|
view?: string;
|
||||||
|
files?: { [key: string]: FileDef };
|
||||||
|
meta?: { [key: string]: any };
|
||||||
|
};
|
||||||
|
|
||||||
|
type FileDef = {
|
||||||
|
filetype?: string;
|
||||||
|
path?: string;
|
||||||
|
url?: string;
|
||||||
|
content?: string;
|
||||||
|
meta?: { [key: string]: any };
|
||||||
|
};
|
||||||
|
|
||||||
|
type TermSize = {
|
||||||
|
rows: number;
|
||||||
|
cols: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Client = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
version: number;
|
||||||
|
mainwindowid: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Tab = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
version: number;
|
||||||
|
name: string;
|
||||||
|
blockids: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type Point = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type WinSize = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Workspace = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
version: number;
|
||||||
|
name: string;
|
||||||
|
tabids: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type RuntimeOpts = {
|
||||||
|
termsize?: TermSize;
|
||||||
|
winsize?: WinSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
type WaveObj = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Window = {
|
||||||
|
otype: string;
|
||||||
|
oid: string;
|
||||||
|
version: number;
|
||||||
|
workspaceid: string;
|
||||||
|
activetabid: string;
|
||||||
|
activeblockmap: { [key: string]: string };
|
||||||
|
pos: Point;
|
||||||
|
winsize: WinSize;
|
||||||
|
lastfocusts: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
2
main.go
2
main.go
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/service/blockservice"
|
"github.com/wavetermdev/thenextwave/pkg/service/blockservice"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/service/clientservice"
|
"github.com/wavetermdev/thenextwave/pkg/service/clientservice"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/service/fileservice"
|
"github.com/wavetermdev/thenextwave/pkg/service/fileservice"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/service/objectservice"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
|
|
||||||
@ -131,6 +132,7 @@ func main() {
|
|||||||
application.NewService(&fileservice.FileService{}),
|
application.NewService(&fileservice.FileService{}),
|
||||||
application.NewService(&blockservice.BlockService{}),
|
application.NewService(&blockservice.BlockService{}),
|
||||||
application.NewService(&clientservice.ClientService{}),
|
application.NewService(&clientservice.ClientService{}),
|
||||||
|
application.NewService(&objectservice.ObjectService{}),
|
||||||
},
|
},
|
||||||
Icon: appIcon,
|
Icon: appIcon,
|
||||||
Assets: application.AssetOptions{
|
Assets: application.AssetOptions{
|
||||||
|
55
pkg/service/objectservice/objectservice.go
Normal file
55
pkg/service/objectservice/objectservice.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package objectservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ObjectService struct{}
|
||||||
|
|
||||||
|
const DefaultTimeout = 2 * time.Second
|
||||||
|
|
||||||
|
func parseORef(oref string) (*waveobj.ORef, error) {
|
||||||
|
fields := strings.Split(oref, ":")
|
||||||
|
if len(fields) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid object reference: %q", oref)
|
||||||
|
}
|
||||||
|
return &waveobj.ORef{OType: fields[0], OID: fields[1]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ObjectService) GetObject(orefStr string) (any, error) {
|
||||||
|
oref, err := parseORef(orefStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
||||||
|
defer cancelFn()
|
||||||
|
obj, err := wstore.DBGetORef(ctx, *oref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting object: %w", err)
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ObjectService) GetObjects(orefStrArr []string) (any, error) {
|
||||||
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
||||||
|
defer cancelFn()
|
||||||
|
|
||||||
|
var orefArr []waveobj.ORef
|
||||||
|
for _, orefStr := range orefStrArr {
|
||||||
|
orefObj, err := parseORef(orefStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
orefArr = append(orefArr, *orefObj)
|
||||||
|
}
|
||||||
|
return wstore.DBSelectORefs(ctx, orefArr)
|
||||||
|
}
|
@ -23,6 +23,11 @@ const (
|
|||||||
VersionGoFieldName = "Version"
|
VersionGoFieldName = "Version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ORef struct {
|
||||||
|
OType string `json:"otype"`
|
||||||
|
OID string `json:"oid"`
|
||||||
|
}
|
||||||
|
|
||||||
type WaveObj interface {
|
type WaveObj interface {
|
||||||
GetOType() string // should not depend on object state (should work with nil value)
|
GetOType() string // should not depend on object state (should work with nil value)
|
||||||
}
|
}
|
||||||
@ -36,35 +41,37 @@ type waveObjDesc struct {
|
|||||||
var waveObjMap = sync.Map{}
|
var waveObjMap = sync.Map{}
|
||||||
var waveObjRType = reflect.TypeOf((*WaveObj)(nil)).Elem()
|
var waveObjRType = reflect.TypeOf((*WaveObj)(nil)).Elem()
|
||||||
|
|
||||||
func RegisterType[T WaveObj]() {
|
func RegisterType(rtype reflect.Type) {
|
||||||
var waveObj T
|
if rtype.Kind() != reflect.Ptr {
|
||||||
|
panic(fmt.Sprintf("wave object must be a pointer for %v", rtype))
|
||||||
|
}
|
||||||
|
if !rtype.Implements(waveObjRType) {
|
||||||
|
panic(fmt.Sprintf("wave object must implement WaveObj for %v", rtype))
|
||||||
|
}
|
||||||
|
waveObj := reflect.Zero(rtype).Interface().(WaveObj)
|
||||||
otype := waveObj.GetOType()
|
otype := waveObj.GetOType()
|
||||||
if otype == "" {
|
if otype == "" {
|
||||||
panic(fmt.Sprintf("otype is empty for %T", waveObj))
|
panic(fmt.Sprintf("otype is empty for %v", rtype))
|
||||||
}
|
|
||||||
rtype := reflect.TypeOf(waveObj)
|
|
||||||
if rtype.Kind() != reflect.Ptr {
|
|
||||||
panic(fmt.Sprintf("wave object must be a pointer for %T", waveObj))
|
|
||||||
}
|
}
|
||||||
oidField, found := rtype.Elem().FieldByName(OIDGoFieldName)
|
oidField, found := rtype.Elem().FieldByName(OIDGoFieldName)
|
||||||
if !found {
|
if !found {
|
||||||
panic(fmt.Sprintf("missing OID field for %T", waveObj))
|
panic(fmt.Sprintf("missing OID field for %v", rtype))
|
||||||
}
|
}
|
||||||
if oidField.Type.Kind() != reflect.String {
|
if oidField.Type.Kind() != reflect.String {
|
||||||
panic(fmt.Sprintf("OID field must be string for %T", waveObj))
|
panic(fmt.Sprintf("OID field must be string for %v", rtype))
|
||||||
}
|
}
|
||||||
if oidField.Tag.Get("json") != OIDKeyName {
|
if oidField.Tag.Get("json") != OIDKeyName {
|
||||||
panic(fmt.Sprintf("OID field json tag must be %q for %T", OIDKeyName, waveObj))
|
panic(fmt.Sprintf("OID field json tag must be %q for %v", OIDKeyName, rtype))
|
||||||
}
|
}
|
||||||
versionField, found := rtype.Elem().FieldByName(VersionGoFieldName)
|
versionField, found := rtype.Elem().FieldByName(VersionGoFieldName)
|
||||||
if !found {
|
if !found {
|
||||||
panic(fmt.Sprintf("missing Version field for %T", waveObj))
|
panic(fmt.Sprintf("missing Version field for %v", rtype))
|
||||||
}
|
}
|
||||||
if versionField.Type.Kind() != reflect.Int {
|
if versionField.Type.Kind() != reflect.Int {
|
||||||
panic(fmt.Sprintf("Version field must be int for %T", waveObj))
|
panic(fmt.Sprintf("Version field must be int for %v", rtype))
|
||||||
}
|
}
|
||||||
if versionField.Tag.Get("json") != VersionKeyName {
|
if versionField.Tag.Get("json") != VersionKeyName {
|
||||||
panic(fmt.Sprintf("Version field json tag must be %q for %T", VersionKeyName, waveObj))
|
panic(fmt.Sprintf("Version field json tag must be %q for %v", VersionKeyName, rtype))
|
||||||
}
|
}
|
||||||
_, found = waveObjMap.Load(otype)
|
_, found = waveObjMap.Load(otype)
|
||||||
if found {
|
if found {
|
||||||
@ -286,16 +293,16 @@ func generateTSTypeInternal(rtype reflect.Type) (string, []reflect.Type) {
|
|||||||
subTypes = append(subTypes, fieldSubTypes...)
|
subTypes = append(subTypes, fieldSubTypes...)
|
||||||
buf.WriteString(fmt.Sprintf(" %s%s: %s;\n", fieldName, optMarker, tsType))
|
buf.WriteString(fmt.Sprintf(" %s%s: %s;\n", fieldName, optMarker, tsType))
|
||||||
}
|
}
|
||||||
buf.WriteString("}\n")
|
buf.WriteString("};\n")
|
||||||
return buf.String(), subTypes
|
return buf.String(), subTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateWaveObjTSType() string {
|
func GenerateWaveObjTSType() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString("type WaveObj {\n")
|
buf.WriteString("type WaveObj = {\n")
|
||||||
buf.WriteString(" otype: string;\n")
|
buf.WriteString(" otype: string;\n")
|
||||||
buf.WriteString(" oid: string;\n")
|
buf.WriteString(" oid: string;\n")
|
||||||
buf.WriteString("}\n")
|
buf.WriteString("};\n")
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ package wstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@ -19,11 +20,9 @@ var TabMap = ds.NewSyncMap[*Tab]()
|
|||||||
var BlockMap = ds.NewSyncMap[*Block]()
|
var BlockMap = ds.NewSyncMap[*Block]()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
waveobj.RegisterType[*Client]()
|
for _, rtype := range AllWaveObjTypes() {
|
||||||
waveobj.RegisterType[*Window]()
|
waveobj.RegisterType(rtype)
|
||||||
waveobj.RegisterType[*Workspace]()
|
}
|
||||||
waveobj.RegisterType[*Tab]()
|
|
||||||
waveobj.RegisterType[*Block]()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@ -36,6 +35,16 @@ func (*Client) GetOType() string {
|
|||||||
return "client"
|
return "client"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AllWaveObjTypes() []reflect.Type {
|
||||||
|
return []reflect.Type{
|
||||||
|
reflect.TypeOf(&Client{}),
|
||||||
|
reflect.TypeOf(&Window{}),
|
||||||
|
reflect.TypeOf(&Workspace{}),
|
||||||
|
reflect.TypeOf(&Tab{}),
|
||||||
|
reflect.TypeOf(&Block{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// stores the ui-context of the window
|
// stores the ui-context of the window
|
||||||
// workspaceid, active tab, active block within each tab, window size, etc.
|
// workspaceid, active tab, active block within each tab, window size, etc.
|
||||||
type Window struct {
|
type Window struct {
|
||||||
@ -147,6 +156,10 @@ func CreateWorkspace() (*Workspace, error) {
|
|||||||
return ws, nil
|
return ws, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetObject(otype string, oid string) (waveobj.WaveObj, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func EnsureInitialData() error {
|
func EnsureInitialData() error {
|
||||||
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer cancelFn()
|
defer cancelFn()
|
||||||
|
@ -14,9 +14,18 @@ func waveObjTableName(w waveobj.WaveObj) string {
|
|||||||
return "db_" + w.GetOType()
|
return "db_" + w.GetOType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tableNameFromOType(otype string) string {
|
||||||
|
return "db_" + otype
|
||||||
|
}
|
||||||
|
|
||||||
func tableNameGen[T waveobj.WaveObj]() string {
|
func tableNameGen[T waveobj.WaveObj]() string {
|
||||||
var zeroObj T
|
var zeroObj T
|
||||||
return "db_" + zeroObj.GetOType()
|
return tableNameFromOType(zeroObj.GetOType())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOTypeGen[T waveobj.WaveObj]() string {
|
||||||
|
var zeroObj T
|
||||||
|
return zeroObj.GetOType()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DBGetCount[T waveobj.WaveObj](ctx context.Context) (int, error) {
|
func DBGetCount[T waveobj.WaveObj](ctx context.Context) (int, error) {
|
||||||
@ -33,13 +42,26 @@ type idDataType struct {
|
|||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func genericCastWithErr[T any](v any, err error) (T, error) {
|
||||||
|
if err != nil {
|
||||||
|
var zeroVal T
|
||||||
|
return zeroVal, err
|
||||||
|
}
|
||||||
|
return v.(T), err
|
||||||
|
}
|
||||||
|
|
||||||
func DBGetSingleton[T waveobj.WaveObj](ctx context.Context) (T, error) {
|
func DBGetSingleton[T waveobj.WaveObj](ctx context.Context) (T, error) {
|
||||||
return WithTxRtn(ctx, func(tx *TxWrap) (T, error) {
|
rtn, err := DBGetSingletonByType(ctx, getOTypeGen[T]())
|
||||||
table := tableNameGen[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)
|
||||||
query := fmt.Sprintf("SELECT oid, version, data FROM %s LIMIT 1", table)
|
query := fmt.Sprintf("SELECT oid, version, data FROM %s LIMIT 1", table)
|
||||||
var row idDataType
|
var row idDataType
|
||||||
tx.Get(&row, query)
|
tx.Get(&row, query)
|
||||||
rtn, err := waveobj.FromJsonGen[T](row.Data)
|
rtn, err := waveobj.FromJson(row.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rtn, err
|
return rtn, err
|
||||||
}
|
}
|
||||||
@ -49,12 +71,17 @@ func DBGetSingleton[T waveobj.WaveObj](ctx context.Context) (T, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DBGet[T waveobj.WaveObj](ctx context.Context, id string) (T, error) {
|
func DBGet[T waveobj.WaveObj](ctx context.Context, id string) (T, error) {
|
||||||
return WithTxRtn(ctx, func(tx *TxWrap) (T, error) {
|
rtn, err := DBGetORef(ctx, waveobj.ORef{OType: getOTypeGen[T](), OID: id})
|
||||||
table := tableNameGen[T]()
|
return genericCastWithErr[T](rtn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DBGetORef(ctx context.Context, oref waveobj.ORef) (waveobj.WaveObj, error) {
|
||||||
|
return WithTxRtn(ctx, func(tx *TxWrap) (waveobj.WaveObj, error) {
|
||||||
|
table := tableNameFromOType(oref.OType)
|
||||||
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid = ?", table)
|
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid = ?", table)
|
||||||
var row idDataType
|
var row idDataType
|
||||||
tx.Get(&row, query, id)
|
tx.Get(&row, query, oref.OID)
|
||||||
rtn, err := waveobj.FromJsonGen[T](row.Data)
|
rtn, err := waveobj.FromJson(row.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rtn, err
|
return rtn, err
|
||||||
}
|
}
|
||||||
@ -63,31 +90,58 @@ func DBGet[T waveobj.WaveObj](ctx context.Context, id string) (T, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DBSelectMap[T waveobj.WaveObj](ctx context.Context, ids []string) (map[string]T, error) {
|
func dbSelectOIDs(ctx context.Context, otype string, oids []string) ([]waveobj.WaveObj, error) {
|
||||||
return WithTxRtn(ctx, func(tx *TxWrap) (map[string]T, error) {
|
return WithTxRtn(ctx, func(tx *TxWrap) ([]waveobj.WaveObj, error) {
|
||||||
table := tableNameGen[T]()
|
table := tableNameFromOType(otype)
|
||||||
var rows []idDataType
|
|
||||||
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid IN (SELECT value FROM json_each(?))", table)
|
query := fmt.Sprintf("SELECT oid, version, data FROM %s WHERE oid IN (SELECT value FROM json_each(?))", table)
|
||||||
tx.Select(&rows, query, ids)
|
var rows []idDataType
|
||||||
rtnMap := make(map[string]T)
|
tx.Select(&rows, query, oids)
|
||||||
|
rtn := make([]waveobj.WaveObj, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
if row.OId == "" || len(row.Data) == 0 {
|
waveObj, err := waveobj.FromJson(row.Data)
|
||||||
continue
|
|
||||||
}
|
|
||||||
waveObj, err := waveobj.FromJsonGen[T](row.Data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
waveobj.SetVersion(waveObj, row.Version)
|
waveobj.SetVersion(waveObj, row.Version)
|
||||||
rtnMap[row.OId] = waveObj
|
rtn = append(rtn, waveObj)
|
||||||
}
|
}
|
||||||
return rtnMap, nil
|
return rtn, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DBDelete[T waveobj.WaveObj](ctx context.Context, id string) error {
|
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...)
|
||||||
|
}
|
||||||
|
return rtn, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
return WithTx(ctx, func(tx *TxWrap) error {
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
table := tableNameGen[T]()
|
table := tableNameFromOType(otype)
|
||||||
query := fmt.Sprintf("DELETE FROM %s WHERE oid = ?", table)
|
query := fmt.Sprintf("DELETE FROM %s WHERE oid = ?", table)
|
||||||
tx.Exec(query, id)
|
tx.Exec(query, id)
|
||||||
return nil
|
return nil
|
||||||
@ -111,7 +165,7 @@ func DBUpdate(ctx context.Context, val waveobj.WaveObj) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DBInsert[T waveobj.WaveObj](ctx context.Context, val T) error {
|
func DBInsert(ctx context.Context, val waveobj.WaveObj) error {
|
||||||
oid := waveobj.GetOID(val)
|
oid := waveobj.GetOID(val)
|
||||||
if oid == "" {
|
if oid == "" {
|
||||||
return fmt.Errorf("cannot insert %T value with empty id", val)
|
return fmt.Errorf("cannot insert %T value with empty id", val)
|
||||||
|
Loading…
Reference in New Issue
Block a user