From 8624e9c844860f6cdbbd22db3557b6fb7c80a42e Mon Sep 17 00:00:00 2001
From: sawka <mike.sawka@gmail.com>
Date: Mon, 5 Dec 2022 22:59:00 -0800
Subject: [PATCH] add line staring to schema and to cmdrunner

---
 db/migrations/000001_init.up.sql |  1 +
 db/schema.sql                    |  9 +++++--
 pkg/cmdrunner/cmdrunner.go       | 42 ++++++++++++++++++++++++++++++++
 pkg/sstore/dbops.go              | 36 ++++++++++++++++++++++++---
 pkg/sstore/sstore.go             |  1 +
 5 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/db/migrations/000001_init.up.sql b/db/migrations/000001_init.up.sql
index b214f60ba..d4d65ed45 100644
--- a/db/migrations/000001_init.up.sql
+++ b/db/migrations/000001_init.up.sql
@@ -97,6 +97,7 @@ CREATE TABLE line (
     cmdid varchar(36) NOT NULL,
     ephemeral boolean NOT NULL,
     contentheight int NOT NULL,
+    star int NOT NULL,
     PRIMARY KEY (sessionid, windowid, lineid)
 );
 
diff --git a/db/schema.sql b/db/schema.sql
index 34d8bbcc4..b35e347b1 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -91,6 +91,7 @@ CREATE TABLE line (
     cmdid varchar(36) NOT NULL,
     ephemeral boolean NOT NULL,
     contentheight int NOT NULL,
+    star int NOT NULL,
     PRIMARY KEY (sessionid, windowid, lineid)
 );
 CREATE TABLE remote (
@@ -118,14 +119,18 @@ CREATE TABLE cmd (
     remoteid varchar(36) NOT NULL,
     remotename varchar(50) NOT NULL,
     cmdstr text NOT NULL,
-    remotestate json NOT NULL,
+    festate json NOT NULL,
+    statebasehash varchar(36) NOT NULL,
+    statediffhasharr json NOT NULL,
     termopts json NOT NULL,
     origtermopts json NOT NULL,
     status varchar(10) NOT NULL,
     startpk json NOT NULL,
-    donepk json NOT NULL,
+    doneinfo json NOT NULL,
     runout json NOT NULL,
     rtnstate bool NOT NULL,
+    rtnbasehash varchar(36) NOT NULL,
+    rtndiffhasharr json NOT NULL,
     PRIMARY KEY (sessionid, cmdid)
 );
 CREATE TABLE history (
diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go
index e516bd369..00db35cb0 100644
--- a/pkg/cmdrunner/cmdrunner.go
+++ b/pkg/cmdrunner/cmdrunner.go
@@ -141,6 +141,7 @@ func init() {
 
 	registerCmdFn("line", LineCommand)
 	registerCmdFn("line:show", LineShowCommand)
+	registerCmdFn("line:star", LineStarCommand)
 
 	registerCmdFn("history", HistoryCommand)
 
@@ -1520,6 +1521,47 @@ func LineCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.
 	return nil, fmt.Errorf("/line requires a subcommand: %s", formatStrs([]string{"show"}, "or", false))
 }
 
+func LineStarCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
+	ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
+	if err != nil {
+		return nil, err
+	}
+	if len(pk.Args) == 0 {
+		return nil, fmt.Errorf("/line:star requires an argument (line number or id)")
+	}
+	if len(pk.Args) > 2 {
+		return nil, fmt.Errorf("/line:star only takes up to 2 arguments (line-number and star-value)")
+	}
+	lineArg := pk.Args[0]
+	lineId, err := sstore.FindLineIdByArg(ctx, ids.SessionId, ids.WindowId, lineArg)
+	if err != nil {
+		return nil, fmt.Errorf("error looking up lineid: %v", err)
+	}
+	if lineId == "" {
+		return nil, fmt.Errorf("line %q not found", lineArg)
+	}
+	starVal, err := resolveNonNegInt(pk.Args[1], 1)
+	if err != nil {
+		return nil, fmt.Errorf("/line:star invalid star-value (not integer): %v", err)
+	}
+	if starVal > 5 {
+		return nil, fmt.Errorf("/line:star invalid star-value must be in the range of 0-5")
+	}
+	err = sstore.UpdateLineStar(ctx, lineId, starVal)
+	if err != nil {
+		return nil, fmt.Errorf("/line:star error updating star value: %v", err)
+	}
+	lineObj, err := sstore.GetLineById(ctx, lineId)
+	if err != nil {
+		return nil, fmt.Errorf("/line:star error getting line: %v", err)
+	}
+	if lineObj == nil {
+		// no line (which is strange given we checked for it above).  just return a nop.
+		return nil, nil
+	}
+	return sstore.ModelUpdate{Line: lineObj}, nil
+}
+
 func LineShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
 	ids, err := resolveUiIds(ctx, pk, R_Session|R_Screen|R_Window)
 	if err != nil {
diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go
index 039887555..d8af3c302 100644
--- a/pkg/sstore/dbops.go
+++ b/pkg/sstore/dbops.go
@@ -569,7 +569,7 @@ func FindLineIdByArg(ctx context.Context, sessionId string, windowId string, lin
 			lineId = tx.GetString(query, sessionId, windowId, lineArg)
 		} else {
 			// id match
-			query := `SELECT * FROM line WHERE sessionid = ? AND windowid = ? AND lineid = ?`
+			query := `SELECT lineid FROM line WHERE sessionid = ? AND windowid = ? AND lineid = ?`
 			lineId = tx.GetString(query, sessionId, windowId, lineArg)
 		}
 		return nil
@@ -652,8 +652,8 @@ func InsertLine(ctx context.Context, line *LineType, cmd *CmdType) error {
 		query = `SELECT nextlinenum FROM window WHERE sessionid = ? AND windowid = ?`
 		nextLineNum := tx.GetInt(query, line.SessionId, line.WindowId)
 		line.LineNum = int64(nextLineNum)
-		query = `INSERT INTO line  ( sessionid, windowid, userid, lineid, ts, linenum, linenumtemp, linelocal, linetype, text, cmdid, ephemeral, contentheight)
-                            VALUES (:sessionid,:windowid,:userid,:lineid,:ts,:linenum,:linenumtemp,:linelocal,:linetype,:text,:cmdid,:ephemeral,:contentheight)`
+		query = `INSERT INTO line  ( sessionid, windowid, userid, lineid, ts, linenum, linenumtemp, linelocal, linetype, text, cmdid, ephemeral, contentheight, star)
+                            VALUES (:sessionid,:windowid,:userid,:lineid,:ts,:linenum,:linenumtemp,:linelocal,:linetype,:text,:cmdid,:ephemeral,:contentheight,:star)`
 		tx.NamedExecWrap(query, line)
 		query = `UPDATE window SET nextlinenum = ? WHERE sessionid = ? AND windowid = ?`
 		tx.ExecWrap(query, nextLineNum+1, line.SessionId, line.WindowId)
@@ -1445,3 +1445,33 @@ func GetFullState(ctx context.Context, ssPtr ShellStatePtr) (*packet.ShellState,
 	}
 	return state, nil
 }
+
+func UpdateLineStar(ctx context.Context, lineId string, starVal int) error {
+	txErr := WithTx(ctx, func(tx *TxWrap) error {
+		query := `UPDATE line SET star = ? WHERE lineid = ?`
+		tx.ExecWrap(query, starVal, lineId)
+		return nil
+	})
+	if txErr != nil {
+		return txErr
+	}
+	return nil
+}
+
+// can return nil, nil if line is not found
+func GetLineById(ctx context.Context, lineId string) (*LineType, error) {
+	var rtn *LineType
+	txErr := WithTx(ctx, func(tx *TxWrap) error {
+		var line LineType
+		query := `SELECT * FROM line WHERE lineid = ?`
+		found := tx.GetWrap(&line, query, lineId)
+		if found {
+			rtn = &line
+		}
+		return nil
+	})
+	if txErr != nil {
+		return nil, txErr
+	}
+	return rtn, nil
+}
diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go
index 688b1a932..3cf6a7f05 100644
--- a/pkg/sstore/sstore.go
+++ b/pkg/sstore/sstore.go
@@ -579,6 +579,7 @@ type LineType struct {
 	Text          string `json:"text,omitempty"`
 	CmdId         string `json:"cmdid,omitempty"`
 	Ephemeral     bool   `json:"ephemeral,omitempty"`
+	Star          bool   `json:"star,omitempty"`
 	Remove        bool   `json:"remove,omitempty"`
 	ContentHeight int64  `json:"contentheight,omitempty"`
 }