setactivetab working, removed tombstones, created updatetype

This commit is contained in:
sawka 2024-05-27 14:31:12 -07:00
parent b87786febf
commit abedca2364
7 changed files with 89 additions and 115 deletions

View File

@ -41,10 +41,7 @@ function isValidWaveObj(val: WaveObj): boolean {
if (val == null) { if (val == null) {
return false; return false;
} }
if (isBlank(val.otype) || isBlank(val.oid)) { if (isBlank(val.otype) || isBlank(val.oid) || isBlankNum(val.version)) {
return false;
}
if (!val.deleted && isBlankNum(val.version)) {
return false; return false;
} }
return true; return true;
@ -151,34 +148,34 @@ function useWaveObject<T>(oref: string): [T, boolean, (T) => void] {
return [atomVal.value, atomVal.loading, simpleSet]; return [atomVal.value, atomVal.loading, simpleSet];
} }
function updateWaveObject(val: WaveObj) { function updateWaveObject(update: WaveObjUpdate) {
if (val == null) { if (update == null) {
return; return;
} }
if (!isValidWaveObj(val)) { let oref = makeORef(update.otype, update.oid);
console.log("invalid wave object", val);
return;
}
let oref = makeORef(val.otype, val.oid);
let wov = waveObjectValueCache.get(oref); let wov = waveObjectValueCache.get(oref);
if (wov == null) { if (wov == null) {
wov = createWaveValueObject(oref, false); wov = createWaveValueObject(oref, false);
waveObjectValueCache.set(oref, wov); waveObjectValueCache.set(oref, wov);
} }
if (val.deleted) { if (update.updatetype == "delete") {
globalStore.set(wov.dataAtom, { value: null, loading: false }); globalStore.set(wov.dataAtom, { value: null, loading: false });
} else { } else {
let curValue: WaveObjectDataItemType<WaveObj> = globalStore.get(wov.dataAtom); if (!isValidWaveObj(update.obj)) {
if (curValue.value != null && curValue.value.version >= val.version) { console.log("invalid wave object update", update);
return; return;
} }
globalStore.set(wov.dataAtom, { value: val, loading: false }); let curValue: WaveObjectDataItemType<WaveObj> = globalStore.get(wov.dataAtom);
if (curValue.value != null && curValue.value.version >= update.obj.version) {
return;
}
globalStore.set(wov.dataAtom, { value: update.obj, loading: false });
} }
wov.holdTime = Date.now() + defaultHoldTime; wov.holdTime = Date.now() + defaultHoldTime;
return; return;
} }
function updateWaveObjects(vals: WaveObj[]) { function updateWaveObjects(vals: WaveObjUpdate[]) {
for (let val of vals) { for (let val of vals) {
updateWaveObject(val); updateWaveObject(val);
} }
@ -194,7 +191,7 @@ function cleanWaveObjectCache() {
} }
Events.On("waveobj:update", (event: any) => { Events.On("waveobj:update", (event: any) => {
const data: WaveObj[] = event?.data; const data: WaveObjUpdate[] = event?.data;
if (data == null) { if (data == null) {
return; return;
} }
@ -217,6 +214,7 @@ function wrapObjectServiceCall<T>(fnName: string, ...args: any[]): Promise<T> {
); );
prtn = prtn.then((val) => { prtn = prtn.then((val) => {
if (val.updates) { if (val.updates) {
console.log(val.updates);
updateWaveObjects(val.updates); updateWaveObjects(val.updates);
} }
return val; return val;
@ -228,6 +226,10 @@ function AddTabToWorkspace(tabName: string, activateTab: boolean): Promise<{ tab
return wrapObjectServiceCall("AddTabToWorkspace", tabName, activateTab); return wrapObjectServiceCall("AddTabToWorkspace", tabName, activateTab);
} }
function SetActiveTab(tabId: string): Promise<void> {
return wrapObjectServiceCall("SetActiveTab", tabId);
}
function getStaticObjectValue<T>(oref: string, getFn: jotai.Getter): T { function getStaticObjectValue<T>(oref: string, getFn: jotai.Getter): T {
let wov = waveObjectValueCache.get(oref); let wov = waveObjectValueCache.get(oref);
if (wov == null) { if (wov == null) {
@ -248,4 +250,5 @@ export {
cleanWaveObjectCache, cleanWaveObjectCache,
getStaticObjectValue, getStaticObjectValue,
AddTabToWorkspace, AddTabToWorkspace,
SetActiveTab,
}; };

View File

@ -24,7 +24,7 @@ function Tab({ tabId }: { tabId: string }) {
if (tabId == null) { if (tabId == null) {
return; return;
} }
// TODO WOS.SetActiveTab(tabId);
} }
return ( return (
<div <div

View File

@ -11,10 +11,20 @@ declare global {
oid: string; oid: string;
}; };
type Block = { type WaveObj = {
otype: string; otype: string;
oid: string; oid: string;
version: number; version: number;
};
type WaveObjUpdate = {
updatetype: "update" | "delete";
otype: string;
oid: string;
obj?: WaveObj;
};
type Block = WaveObj & {
blockdef: BlockDef; blockdef: BlockDef;
controller: string; controller: string;
view: string; view: string;
@ -80,13 +90,6 @@ declare global {
winsize?: WinSize; winsize?: WinSize;
}; };
type WaveObj = {
otype: string;
oid: string;
version: number;
deleted?: boolean;
};
type WaveWindow = { type WaveWindow = {
otype: string; otype: string;
oid: string; oid: string;

View File

@ -5,6 +5,7 @@ package objectservice
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -60,21 +61,18 @@ func updatesRtn(ctx context.Context, rtnVal map[string]any) (any, error) {
if len(updates) == 0 { if len(updates) == 0 {
return nil, nil return nil, nil
} }
var rtn []any updateArr := make([]wstore.WaveObjUpdate, 0, len(updates))
for _, obj := range updates { for _, update := range updates {
if obj == nil { updateArr = append(updateArr, update)
continue }
} jval, err := json.Marshal(updateArr)
jmap, err := waveobj.ToJsonMap(obj) if err != nil {
if err != nil { return nil, fmt.Errorf("error converting updates to JSON: %w", err)
return nil, fmt.Errorf("error converting object to JSON: %w", err)
}
rtn = append(rtn, jmap)
} }
if rtnVal == nil { if rtnVal == nil {
rtnVal = make(map[string]any) rtnVal = make(map[string]any)
} }
rtnVal["updates"] = rtn rtnVal["updates"] = json.RawMessage(jval)
return rtnVal, nil return rtnVal, nil
} }

View File

@ -18,7 +18,6 @@ const (
OTypeKeyName = "otype" OTypeKeyName = "otype"
OIDKeyName = "oid" OIDKeyName = "oid"
VersionKeyName = "version" VersionKeyName = "version"
DeletedKeyName = "deleted"
OIDGoFieldName = "OID" OIDGoFieldName = "OID"
VersionGoFieldName = "Version" VersionGoFieldName = "Version"
@ -33,15 +32,6 @@ 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)
} }
type WaveObjTombstone struct {
OType string `json:"otype"`
OID string `json:"oid"`
}
func (w *WaveObjTombstone) GetOType() string {
return w.OType
}
type waveObjDesc struct { type waveObjDesc struct {
RType reflect.Type RType reflect.Type
OIDField reflect.StructField OIDField reflect.StructField
@ -103,9 +93,6 @@ func getWaveObjDesc(otype string) *waveObjDesc {
} }
func GetOID(waveObj WaveObj) string { func GetOID(waveObj WaveObj) string {
if tomb, ok := waveObj.(*WaveObjTombstone); ok {
return tomb.OID
}
desc := getWaveObjDesc(waveObj.GetOType()) desc := getWaveObjDesc(waveObj.GetOType())
if desc == nil { if desc == nil {
return "" return ""
@ -114,10 +101,6 @@ func GetOID(waveObj WaveObj) string {
} }
func SetOID(waveObj WaveObj, oid string) { func SetOID(waveObj WaveObj, oid string) {
if tomb, ok := waveObj.(*WaveObjTombstone); ok {
tomb.OID = oid
return
}
desc := getWaveObjDesc(waveObj.GetOType()) desc := getWaveObjDesc(waveObj.GetOType())
if desc == nil { if desc == nil {
return return
@ -126,9 +109,6 @@ func SetOID(waveObj WaveObj, oid string) {
} }
func GetVersion(waveObj WaveObj) int { func GetVersion(waveObj WaveObj) int {
if _, ok := waveObj.(*WaveObjTombstone); ok {
return 0
}
desc := getWaveObjDesc(waveObj.GetOType()) desc := getWaveObjDesc(waveObj.GetOType())
if desc == nil { if desc == nil {
return 0 return 0
@ -137,9 +117,6 @@ func GetVersion(waveObj WaveObj) int {
} }
func SetVersion(waveObj WaveObj, version int) { func SetVersion(waveObj WaveObj, version int) {
if _, ok := waveObj.(*WaveObjTombstone); ok {
return
}
desc := getWaveObjDesc(waveObj.GetOType()) desc := getWaveObjDesc(waveObj.GetOType())
if desc == nil { if desc == nil {
return return
@ -161,10 +138,6 @@ func ToJsonMap(w WaveObj) (map[string]any, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, ok := w.(*WaveObjTombstone); ok {
m[DeletedKeyName] = true
return m, nil
}
m[OTypeKeyName] = w.GetOType() m[OTypeKeyName] = w.GetOType()
m[OIDKeyName] = GetOID(w) m[OIDKeyName] = GetOID(w)
m[VersionKeyName] = GetVersion(w) m[VersionKeyName] = GetVersion(w)
@ -179,39 +152,12 @@ func ToJson(w WaveObj) ([]byte, error) {
return json.Marshal(m) return json.Marshal(m)
} }
func getMapBoolVal(m map[string]any, key string) bool {
val, ok := m[key].(bool)
if !ok {
return false
}
return val
}
func getMapStringVal(m map[string]any, key string) string {
val, ok := m[key].(string)
if !ok {
return ""
}
return val
}
func IsTombstone(w WaveObj) bool {
_, ok := w.(*WaveObjTombstone)
return ok
}
func FromJson(data []byte) (WaveObj, error) { func FromJson(data []byte) (WaveObj, error) {
var m map[string]any var m map[string]any
err := json.Unmarshal(data, &m) err := json.Unmarshal(data, &m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if getMapBoolVal(m, DeletedKeyName) {
return &WaveObjTombstone{
OType: getMapStringVal(m, OTypeKeyName),
OID: getMapStringVal(m, OIDKeyName),
}, nil
}
otype, ok := m[OTypeKeyName].(string) otype, ok := m[OTypeKeyName].(string)
if !ok { if !ok {
return nil, fmt.Errorf("missing otype") return nil, fmt.Errorf("missing otype")
@ -328,13 +274,12 @@ func generateTSTypeInternal(rtype reflect.Type) (string, []reflect.Type) {
if tsRename, ok := tsRenameMap[tsTypeName]; ok { if tsRename, ok := tsRenameMap[tsTypeName]; ok {
tsTypeName = tsRename tsTypeName = tsRename
} }
buf.WriteString(fmt.Sprintf("type %s = {\n", tsTypeName))
var isWaveObj bool var isWaveObj bool
if rtype.Implements(waveObjType) || reflect.PointerTo(rtype).Implements(waveObjType) { if rtype.Implements(waveObjType) || reflect.PointerTo(rtype).Implements(waveObjType) {
isWaveObj = true isWaveObj = true
buf.WriteString(fmt.Sprintf(" %s: string;\n", OTypeKeyName)) buf.WriteString(fmt.Sprintf("type %s = WaveObj & {\n", tsTypeName))
buf.WriteString(fmt.Sprintf(" %s: string;\n", OIDKeyName)) } else {
buf.WriteString(fmt.Sprintf(" %s: number;\n", VersionKeyName)) buf.WriteString(fmt.Sprintf("type %s = {\n", tsTypeName))
} }
var subTypes []reflect.Type var subTypes []reflect.Type
for i := 0; i < rtype.NumField(); i++ { for i := 0; i < rtype.NumField(); i++ {

View File

@ -6,6 +6,7 @@ package wstore
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/json"
"fmt" "fmt"
"log" "log"
"reflect" "reflect"
@ -25,7 +26,7 @@ func init() {
} }
type contextUpdatesType struct { type contextUpdatesType struct {
UpdatesStack []map[waveobj.ORef]waveobj.WaveObj UpdatesStack []map[waveobj.ORef]WaveObjUpdate
} }
func dumpUpdateStack(updates *contextUpdatesType) { func dumpUpdateStack(updates *contextUpdatesType) {
@ -47,11 +48,11 @@ func ContextWithUpdates(ctx context.Context) context.Context {
return ctx return ctx
} }
return context.WithValue(ctx, waveObjUpdateKey, &contextUpdatesType{ return context.WithValue(ctx, waveObjUpdateKey, &contextUpdatesType{
UpdatesStack: []map[waveobj.ORef]waveobj.WaveObj{make(map[waveobj.ORef]waveobj.WaveObj)}, UpdatesStack: []map[waveobj.ORef]WaveObjUpdate{make(map[waveobj.ORef]WaveObjUpdate)},
}) })
} }
func ContextGetUpdates(ctx context.Context) map[waveobj.ORef]waveobj.WaveObj { func ContextGetUpdates(ctx context.Context) map[waveobj.ORef]WaveObjUpdate {
updatesVal := ctx.Value(waveObjUpdateKey) updatesVal := ctx.Value(waveObjUpdateKey)
if updatesVal == nil { if updatesVal == nil {
return nil return nil
@ -60,7 +61,7 @@ func ContextGetUpdates(ctx context.Context) map[waveobj.ORef]waveobj.WaveObj {
if len(updates.UpdatesStack) == 1 { if len(updates.UpdatesStack) == 1 {
return updates.UpdatesStack[0] return updates.UpdatesStack[0]
} }
rtn := make(map[waveobj.ORef]waveobj.WaveObj) rtn := make(map[waveobj.ORef]WaveObjUpdate)
for _, update := range updates.UpdatesStack { for _, update := range updates.UpdatesStack {
for k, v := range update { for k, v := range update {
rtn[k] = v rtn[k] = v
@ -69,7 +70,7 @@ func ContextGetUpdates(ctx context.Context) map[waveobj.ORef]waveobj.WaveObj {
return rtn return rtn
} }
func ContextGetUpdate(ctx context.Context, oref waveobj.ORef) waveobj.WaveObj { func ContextGetUpdate(ctx context.Context, oref waveobj.ORef) *WaveObjUpdate {
updatesVal := ctx.Value(waveObjUpdateKey) updatesVal := ctx.Value(waveObjUpdateKey)
if updatesVal == nil { if updatesVal == nil {
return nil return nil
@ -77,23 +78,23 @@ func ContextGetUpdate(ctx context.Context, oref waveobj.ORef) waveobj.WaveObj {
updates := updatesVal.(*contextUpdatesType) updates := updatesVal.(*contextUpdatesType)
for idx := len(updates.UpdatesStack) - 1; idx >= 0; idx-- { for idx := len(updates.UpdatesStack) - 1; idx >= 0; idx-- {
if obj, ok := updates.UpdatesStack[idx][oref]; ok { if obj, ok := updates.UpdatesStack[idx][oref]; ok {
return obj return &obj
} }
} }
return nil return nil
} }
func ContextAddUpdate(ctx context.Context, obj waveobj.WaveObj) { func ContextAddUpdate(ctx context.Context, update WaveObjUpdate) {
updatesVal := ctx.Value(waveObjUpdateKey) updatesVal := ctx.Value(waveObjUpdateKey)
if updatesVal == nil { if updatesVal == nil {
return return
} }
updates := updatesVal.(*contextUpdatesType) updates := updatesVal.(*contextUpdatesType)
oref := waveobj.ORef{ oref := waveobj.ORef{
OType: obj.GetOType(), OType: update.OType,
OID: waveobj.GetOID(obj), OID: update.OID,
} }
updates.UpdatesStack[len(updates.UpdatesStack)-1][oref] = obj updates.UpdatesStack[len(updates.UpdatesStack)-1][oref] = update
} }
func ContextUpdatesBeginTx(ctx context.Context) context.Context { func ContextUpdatesBeginTx(ctx context.Context) context.Context {
@ -102,7 +103,7 @@ func ContextUpdatesBeginTx(ctx context.Context) context.Context {
return ctx return ctx
} }
updates := updatesVal.(*contextUpdatesType) updates := updatesVal.(*contextUpdatesType)
updates.UpdatesStack = append(updates.UpdatesStack, make(map[waveobj.ORef]waveobj.WaveObj)) updates.UpdatesStack = append(updates.UpdatesStack, make(map[waveobj.ORef]WaveObjUpdate))
return ctx return ctx
} }
@ -136,6 +137,36 @@ func ContextUpdatesRollbackTx(ctx context.Context) {
updates.UpdatesStack = updates.UpdatesStack[:len(updates.UpdatesStack)-1] updates.UpdatesStack = updates.UpdatesStack[:len(updates.UpdatesStack)-1]
} }
type WaveObjTombstone struct {
OType string `json:"otype"`
OID string `json:"oid"`
}
const (
UpdateType_Update = "update"
UpdateType_Delete = "delete"
)
type WaveObjUpdate struct {
UpdateType string `json:"updatetype"`
OType string `json:"otype"`
OID string `json:"oid"`
Obj waveobj.WaveObj `json:"obj,omitempty"`
}
func (update WaveObjUpdate) MarshalJSON() ([]byte, error) {
rtn := make(map[string]any)
rtn["updatetype"] = update.UpdateType
rtn["otype"] = update.OType
rtn["oid"] = update.OID
var err error
rtn["obj"], err = waveobj.ToJsonMap(update.Obj)
if err != nil {
return nil, err
}
return json.Marshal(rtn)
}
type UIContext struct { type UIContext struct {
WindowId string `json:"windowid"` WindowId string `json:"windowid"`
} }

View File

@ -159,15 +159,12 @@ func DBDelete(ctx context.Context, otype string, id string) error {
table := tableNameFromOType(otype) 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)
ContextAddUpdate(ctx, &waveobj.WaveObjTombstone{OType: otype, OID: id}) ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Delete, OType: otype, OID: id})
return nil return nil
}) })
} }
func DBUpdate(ctx context.Context, val waveobj.WaveObj) error { func DBUpdate(ctx context.Context, val waveobj.WaveObj) error {
if waveobj.IsTombstone(val) {
return fmt.Errorf("cannot update deleted object")
}
oid := waveobj.GetOID(val) oid := waveobj.GetOID(val)
if oid == "" { if oid == "" {
return fmt.Errorf("cannot update %T value with empty id", val) return fmt.Errorf("cannot update %T value with empty id", val)
@ -181,15 +178,12 @@ func DBUpdate(ctx context.Context, val waveobj.WaveObj) error {
query := fmt.Sprintf("UPDATE %s SET data = ?, version = version+1 WHERE oid = ? RETURNING version", table) query := fmt.Sprintf("UPDATE %s SET data = ?, version = version+1 WHERE oid = ? RETURNING version", table)
newVersion := tx.GetInt(query, jsonData, oid) newVersion := tx.GetInt(query, jsonData, oid)
waveobj.SetVersion(val, newVersion) waveobj.SetVersion(val, newVersion)
ContextAddUpdate(ctx, val) ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Update, OType: val.GetOType(), OID: oid, Obj: val})
return nil return nil
}) })
} }
func DBInsert(ctx context.Context, val waveobj.WaveObj) error { func DBInsert(ctx context.Context, val waveobj.WaveObj) error {
if waveobj.IsTombstone(val) {
return fmt.Errorf("cannot insert deleted object")
}
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)
@ -203,7 +197,7 @@ func DBInsert(ctx context.Context, val waveobj.WaveObj) error {
waveobj.SetVersion(val, 1) waveobj.SetVersion(val, 1)
query := fmt.Sprintf("INSERT INTO %s (oid, version, data) VALUES (?, ?, ?)", table) query := fmt.Sprintf("INSERT INTO %s (oid, version, data) VALUES (?, ?, ?)", table)
tx.Exec(query, oid, 1, jsonData) tx.Exec(query, oid, 1, jsonData)
ContextAddUpdate(ctx, val) ContextAddUpdate(ctx, WaveObjUpdate{UpdateType: UpdateType_Update, OType: val.GetOType(), OID: oid, Obj: val})
return nil return nil
}) })
} }