Skip to content

Commit f4dc4b7

Browse files
committed
feat: switch to postgres for database tools
Addresses obot-platform/obot#2265 Signed-off-by: Nick Hale <[email protected]>
1 parent ba8be10 commit f4dc4b7

File tree

8 files changed

+274
-331
lines changed

8 files changed

+274
-331
lines changed

database/go.mod

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,3 @@
11
module obot-platform/database
22

33
go 1.23.3
4-
5-
require (
6-
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250222170845-eee4337500a6
7-
github.com/ncruces/go-sqlite3 v0.20.3
8-
)
9-
10-
require (
11-
github.com/getkin/kin-openapi v0.129.0 // indirect
12-
github.com/go-openapi/jsonpointer v0.21.0 // indirect
13-
github.com/go-openapi/swag v0.23.0 // indirect
14-
github.com/josharian/intern v1.0.0 // indirect
15-
github.com/mailru/easyjson v0.9.0 // indirect
16-
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
17-
github.com/ncruces/julianday v1.0.0 // indirect
18-
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 // indirect
19-
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 // indirect
20-
github.com/perimeterx/marshmallow v1.1.5 // indirect
21-
github.com/tetratelabs/wazero v1.8.2 // indirect
22-
golang.org/x/sys v0.27.0 // indirect
23-
gopkg.in/yaml.v3 v3.0.1 // indirect
24-
)

database/go.sum

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +0,0 @@
1-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2-
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3-
github.com/getkin/kin-openapi v0.129.0 h1:QGYTNcmyP5X0AtFQ2Dkou9DGBJsUETeLH9rFrJXZh30=
4-
github.com/getkin/kin-openapi v0.129.0/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI=
5-
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
6-
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
7-
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
8-
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
9-
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
10-
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
11-
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250222170845-eee4337500a6 h1:vsZ09cWfNWUXT6AOVQc1GpfEdIxcLusUs6Hgo9IgAKs=
12-
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250222170845-eee4337500a6/go.mod h1:QvGPZoRuAiA8P5EzPI05kTrs+LZ0ipHywUGsKruSknw=
13-
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
14-
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
15-
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
16-
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
17-
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
18-
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
19-
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
20-
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
21-
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
22-
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
23-
github.com/ncruces/go-sqlite3 v0.20.3 h1:+4G4uEqOeusF0yRuQVUl9fuoEebUolwQSnBUjYBLYIw=
24-
github.com/ncruces/go-sqlite3 v0.20.3/go.mod h1:ojLIAB243gtz68Eo283Ps+k9PyR3dvzS+9/RgId4+AA=
25-
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
26-
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
27-
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 h1:nZspmSkneBbtxU9TopEAE0CY+SBJLxO8LPUlw2vG4pU=
28-
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8=
29-
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 h1:t05Ww3DxZutOqbMN+7OIuqDwXbhl32HiZGpLy26BAPc=
30-
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
31-
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
32-
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
33-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
34-
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
35-
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
36-
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
37-
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
38-
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
39-
github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
40-
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
41-
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
42-
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
43-
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
44-
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
45-
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
46-
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
47-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
48-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
49-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
50-
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
51-
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

database/main.go

Lines changed: 29 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,60 @@ package main
22

33
import (
44
"context"
5-
"crypto/sha256"
6-
"encoding/hex"
7-
"errors"
85
"fmt"
9-
"os"
10-
"slices"
11-
126
"obot-platform/database/pkg/cmd"
13-
14-
"github.com/gptscript-ai/go-gptscript"
15-
_ "github.com/ncruces/go-sqlite3/driver"
16-
_ "github.com/ncruces/go-sqlite3/embed"
7+
"os"
178
)
189

19-
var workspaceID = os.Getenv("DATABASE_WORKSPACE_ID")
20-
2110
func main() {
2211
if len(os.Args) != 2 {
2312
fmt.Println("Usage: gptscript-go-tool <command>")
2413
os.Exit(1)
2514
}
2615
command := os.Args[1]
16+
ctx := context.Background()
2717

28-
g, err := gptscript.NewGPTScript()
29-
if err != nil {
30-
fmt.Printf("Error creating GPTScript: %v\n", err)
31-
os.Exit(1)
18+
workspaceID := os.Getenv("DATABASE_WORKSPACE_ID")
19+
if workspaceID == "" {
20+
// TODO(njhale): Figure out why DATABASE_WORKSPACE_ID is not set here for the UI tools.
21+
workspaceID = os.Getenv("GPTSCRIPT_WORKSPACE_ID")
3222
}
33-
defer g.Close()
34-
35-
var (
36-
ctx = context.Background()
37-
dbFileName = "obot.db"
38-
dbWorkspacePath = "/databases/" + dbFileName
39-
revisionID string = "-1"
40-
initialDBData []byte
41-
)
42-
43-
workspaceDB, err := g.ReadFileWithRevisionInWorkspace(ctx, dbWorkspacePath, gptscript.ReadFileInWorkspaceOptions{
44-
WorkspaceID: workspaceID,
45-
})
4623

47-
var notFoundErr *gptscript.NotFoundInWorkspaceError
48-
if err != nil && !errors.As(err, &notFoundErr) {
49-
fmt.Printf("Error reading DB file: %v\n", err)
50-
os.Exit(1)
51-
}
24+
// Get admin DSN from environment variable
25+
adminDSN := os.Getenv("POSTGRES_DSN")
5226

53-
// Create a temporary file for the SQLite database
54-
dbFile, err := os.CreateTemp("", dbFileName)
27+
// Setup database and user with admin credentials
28+
dsn, err := cmd.EnsureTenantSchema(ctx, adminDSN, workspaceID)
5529
if err != nil {
56-
fmt.Printf("Error creating temp file: %v\n", err)
30+
fmt.Printf("Error setting up database: %v\n", err)
5731
os.Exit(1)
5832
}
59-
defer dbFile.Close()
60-
defer os.Remove(dbFile.Name())
6133

62-
// Write the data to the temporary file
63-
if workspaceDB != nil && workspaceDB.Content != nil {
64-
initialDBData = workspaceDB.Content
65-
if err := os.WriteFile(dbFile.Name(), initialDBData, 0644); err != nil {
66-
fmt.Printf("Error writing to temp file: %v\n", err)
67-
os.Exit(1)
68-
}
69-
if workspaceDB.RevisionID != "" {
70-
revisionID = workspaceDB.RevisionID
71-
}
72-
}
73-
74-
// Run the requested command
34+
// Run the requested command using the user credentials
7535
var result string
7636
switch command {
7737
case "listDatabaseTables":
78-
result, err = cmd.ListDatabaseTables(ctx, dbFile)
38+
result, err = cmd.ListDatabaseTables(ctx, dsn)
39+
7940
case "listDatabaseTableRows":
80-
result, err = cmd.ListDatabaseTableRows(ctx, dbFile, os.Getenv("TABLE"))
41+
table := os.Getenv("TABLE")
42+
if table == "" {
43+
err = fmt.Errorf("TABLE environment variable is required")
44+
break
45+
}
46+
result, err = cmd.ListDatabaseTableRows(ctx, dsn, table)
47+
8148
case "runDatabaseSQL":
82-
result, err = cmd.RunDatabaseCommand(ctx, dbFile, os.Getenv("SQL"), "-header")
83-
if err == nil {
84-
err = saveWorkspaceDB(ctx, g, dbWorkspacePath, revisionID, dbFile, initialDBData)
49+
sql := os.Getenv("SQL")
50+
if sql == "" {
51+
err = fmt.Errorf("SQL environment variable is required")
52+
break
8553
}
54+
result, err = cmd.RunDatabaseCommand(ctx, dsn, sql)
55+
8656
case "databaseContext":
87-
result, err = cmd.DatabaseContext(ctx, dbFile)
57+
result, err = cmd.DatabaseContext(ctx, dsn)
58+
8859
default:
8960
err = fmt.Errorf("unknown command: %s", command)
9061
}
@@ -96,66 +67,3 @@ func main() {
9667

9768
fmt.Print(result)
9869
}
99-
100-
// saveWorkspaceDB saves the updated database file to the workspace if the content of the database has changed.
101-
func saveWorkspaceDB(
102-
ctx context.Context,
103-
g *gptscript.GPTScript,
104-
dbWorkspacePath string,
105-
revisionID string,
106-
dbFile *os.File,
107-
initialDBData []byte,
108-
) error {
109-
updatedDBData, err := os.ReadFile(dbFile.Name())
110-
if err != nil {
111-
return fmt.Errorf("Error reading updated DB file: %v", err)
112-
}
113-
114-
if hash(initialDBData) == hash(updatedDBData) {
115-
return nil
116-
}
117-
118-
if err := g.WriteFileInWorkspace(ctx, dbWorkspacePath, updatedDBData, gptscript.WriteFileInWorkspaceOptions{
119-
WorkspaceID: workspaceID,
120-
CreateRevision: &([]bool{true}[0]),
121-
LatestRevisionID: revisionID,
122-
}); err != nil {
123-
return fmt.Errorf("Error writing updated DB file to workspace: %v", err)
124-
}
125-
126-
// Delete old revisions after successfully writing the new revision
127-
revisions, err := g.ListRevisionsForFileInWorkspace(ctx, dbWorkspacePath, gptscript.ListRevisionsForFileInWorkspaceOptions{
128-
WorkspaceID: workspaceID,
129-
})
130-
if err != nil {
131-
fmt.Fprintf(os.Stderr, "Error listing revisions: %v\n", err)
132-
return nil
133-
}
134-
135-
lastRevisionIndex := slices.IndexFunc(revisions, func(rev gptscript.FileInfo) bool {
136-
return rev.RevisionID == revisionID
137-
})
138-
139-
if lastRevisionIndex < 0 {
140-
return nil
141-
}
142-
143-
for _, rev := range revisions[:lastRevisionIndex+1] {
144-
if err := g.DeleteRevisionForFileInWorkspace(ctx, dbWorkspacePath, rev.RevisionID, gptscript.DeleteRevisionForFileInWorkspaceOptions{
145-
WorkspaceID: workspaceID,
146-
}); err != nil {
147-
fmt.Fprintf(os.Stderr, "Error deleting revision %s: %v\n", rev.RevisionID, err)
148-
}
149-
}
150-
151-
return nil
152-
}
153-
154-
// hash computes the SHA-256 hash of the given data and returns it as a hexadecimal string
155-
func hash(data []byte) string {
156-
if data == nil {
157-
return ""
158-
}
159-
hash := sha256.Sum256(data)
160-
return hex.EncodeToString(hash[:])
161-
}

0 commit comments

Comments
 (0)