some work on the query/invalidation engine

This commit is contained in:
2026-04-23 02:35:23 -05:00
parent c1c8950f24
commit e623ed1c52
2 changed files with 66 additions and 24 deletions
+46 -12
View File
@@ -1,6 +1,7 @@
package tether
import (
"encoding/json"
"log/slog"
"net/http"
@@ -9,11 +10,12 @@ import (
)
type Engine struct {
db *gorm.DB
dbType string // sqlite or postgres
mutations map[string]func(ctx *MutationCtx) error
queries map[string]func(ctx *QueryCtx) error
tracker *reactivity.Tracker
db *gorm.DB
dbType string // sqlite or postgres
mutations map[string]func(ctx *MutationCtx) error
queries map[string]func(ctx *QueryCtx) error
dependencies map[string][]string
tracker *reactivity.Tracker
}
func NewEngine(db *gorm.DB, dbType string) *Engine {
@@ -22,7 +24,14 @@ func NewEngine(db *gorm.DB, dbType string) *Engine {
if dbType != "sqlite" && dbType != "postgres" {
panic("Invalid database type")
}
return &Engine{db: db, dbType: dbType, mutations: make(map[string]func(ctx *MutationCtx) error), queries: make(map[string]func(ctx *QueryCtx) error), tracker: tracker}
e := &Engine{db: db, dbType: dbType, mutations: make(map[string]func(ctx *MutationCtx) error), queries: make(map[string]func(ctx *QueryCtx) error), dependencies: make(map[string][]string), tracker: tracker}
db.Callback().Create().After("gorm:create").Register("tether:after_create", func(tx *gorm.DB) {
if dbType == "postgres" {
return
}
e.InvalidateTable(tx.Statement.Table)
})
return e
}
func (e *Engine) RegisterMutation(name string, mutation func(ctx *MutationCtx) error) {
@@ -32,6 +41,9 @@ func (e *Engine) RegisterMutation(name string, mutation func(ctx *MutationCtx) e
func (e *Engine) RegisterQuery(name string, query func(ctx *QueryCtx) error, dependencies []string) {
e.queries[name] = query // stores the query in the list of valid queries
for _, dependency := range dependencies {
e.dependencies[dependency] = append(e.dependencies[dependency], name)
}
slog.Debug("Registered query", "name", name)
}
@@ -56,13 +68,36 @@ func (e *Engine) OnDisconnect(clientID string) error {
return nil
}
func (e *Engine) ExecuteQuery(query string) (interface{}, error) {
func (e *Engine) GetDependentQueries(tableName string) []string {
return e.dependencies[tableName]
}
func (e *Engine) InvalidateTable(tableName string) {
slog.Debug("Invalidating table", "table", tableName)
dependentQueries := e.GetDependentQueries(tableName)
for _, query := range dependentQueries {
slog.Debug("Invalidating query", "query", query)
subscriptions := e.tracker.GetQuerySubscriptions(query)
for _, subscription := range subscriptions {
slog.Debug("Invalidating subscription", "subscription", subscription["clientID"])
params := map[string]interface{}{}
json.Unmarshal([]byte(subscription["params"]), &params)
_, err := e.ExecuteQuery(query, params)
if err != nil {
slog.Error("Failed to execute query", "error", err)
continue
}
}
}
}
func (e *Engine) ExecuteQuery(query string, params map[string]interface{}) (interface{}, error) {
/*
TODO: implement the logic to execute the query
Steps needed:
1. Check which tables updated
2. Get the queries that rely on the tables
3. Get the subscriptions that need updating
1. Check which tables updated
2. Get the queries that rely on the tables
3. Get the subscriptions that need updating
4. Calculate hash for every query
5. Send the updated queries if hash changed
*/
@@ -78,8 +113,7 @@ func (e *Engine) OnReceiveMessage(clientID string, msg map[string]interface{}) e
slog.Debug("Received message", "from", clientID, "message", msg)
switch msg["type"] {
case "query":
query := msg["location"].(string) + "?" + msg["params"].(string)
e.tracker.SubscribeToQuery(clientID, query)
e.tracker.SubscribeToQuery(clientID, msg["location"].(string), msg["params"].(map[string]string))
case "mutation":
e.ExecuteMutation(msg["location"].(string), msg["params"].(map[string]interface{}))
}