Merge pull request #993 from trheyi/main

Refactor DSL management by introducing IO interfaces for database and…
This commit is contained in:
Max 2025-07-15 13:02:22 +08:00 committed by GitHub
commit c60a25ddea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 315 additions and 174 deletions

View file

@ -9,11 +9,13 @@ import (
// YaoAPI is the MCP client DSL manager // YaoAPI is the MCP client DSL manager
type YaoAPI struct { type YaoAPI struct {
root string // The relative path of the MCP client DSL root string // The relative path of the MCP client DSL
fs types.IO // The file system IO interface
db types.IO // The database IO interface
} }
// New returns a new connector DSL manager // New returns a new connector DSL manager
func New(root string) types.Manager { func New(root string, fs types.IO, db types.IO) types.Manager {
return &YaoAPI{root: root} return &YaoAPI{root: root, fs: fs, db: db}
} }
// Loaded return all loaded DSLs // Loaded return all loaded DSLs
@ -22,17 +24,17 @@ func (api *YaoAPI) Loaded(ctx context.Context) (map[string]*types.Info, error) {
} }
// Load will unload the DSL first, then load the DSL from DB or file system // Load will unload the DSL first, then load the DSL from DB or file system
func (api *YaoAPI) Load(ctx context.Context, id string, options interface{}) error { func (api *YaoAPI) Load(ctx context.Context, options *types.LoadOptions) error {
return nil return nil
} }
// Reload will unload the DSL first, then reload the DSL from DB or file system // Reload will unload the DSL first, then reload the DSL from DB or file system
func (api *YaoAPI) Reload(ctx context.Context, id string, options interface{}) error { func (api *YaoAPI) Reload(ctx context.Context, options *types.ReloadOptions) error {
return nil return nil
} }
// Unload will unload the DSL from memory // Unload will unload the DSL from memory
func (api *YaoAPI) Unload(ctx context.Context, id string, options interface{}) error { func (api *YaoAPI) Unload(ctx context.Context, options *types.UnloadOptions) error {
return nil return nil
} }
@ -42,6 +44,6 @@ func (api *YaoAPI) Validate(ctx context.Context, source string) (bool, []types.L
} }
// Execute will execute the DSL // Execute will execute the DSL
func (api *YaoAPI) Execute(ctx context.Context, method string, args ...any) (any, error) { func (api *YaoAPI) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return nil, nil return nil, nil
} }

View file

@ -9,11 +9,13 @@ import (
// YaoConnector is the connector DSL manager // YaoConnector is the connector DSL manager
type YaoConnector struct { type YaoConnector struct {
root string // The relative path of the connector DSL root string // The relative path of the connector DSL
fs types.IO // The file system IO interface
db types.IO // The database IO interface
} }
// New returns a new connector DSL manager // New returns a new connector DSL manager
func New(root string) types.Manager { func New(root string, fs types.IO, db types.IO) types.Manager {
return &YaoConnector{root: root} return &YaoConnector{root: root, fs: fs, db: db}
} }
// Loaded return all loaded DSLs // Loaded return all loaded DSLs
@ -22,17 +24,17 @@ func (c *YaoConnector) Loaded(ctx context.Context) (map[string]*types.Info, erro
} }
// Load will unload the DSL first, then load the DSL from DB or file system // Load will unload the DSL first, then load the DSL from DB or file system
func (c *YaoConnector) Load(ctx context.Context, id string, options interface{}) error { func (c *YaoConnector) Load(ctx context.Context, options *types.LoadOptions) error {
return nil return nil
} }
// Unload will unload the DSL from memory // Unload will unload the DSL from memory
func (c *YaoConnector) Unload(ctx context.Context, id string, options interface{}) error { func (c *YaoConnector) Unload(ctx context.Context, options *types.UnloadOptions) error {
return nil return nil
} }
// Reload will unload the DSL first, then reload the DSL from DB or file system // Reload will unload the DSL first, then reload the DSL from DB or file system
func (c *YaoConnector) Reload(ctx context.Context, id string, options interface{}) error { func (c *YaoConnector) Reload(ctx context.Context, options *types.ReloadOptions) error {
return nil return nil
} }
@ -42,6 +44,6 @@ func (c *YaoConnector) Validate(ctx context.Context, source string) (bool, []typ
} }
// Execute will execute the DSL // Execute will execute the DSL
func (c *YaoConnector) Execute(ctx context.Context, method string, args ...any) (any, error) { func (c *YaoConnector) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return nil, nil return nil, nil
} }

View file

@ -6,6 +6,7 @@ import (
"github.com/yaoapp/yao/dsl/api" "github.com/yaoapp/yao/dsl/api"
"github.com/yaoapp/yao/dsl/connector" "github.com/yaoapp/yao/dsl/connector"
"github.com/yaoapp/yao/dsl/io"
"github.com/yaoapp/yao/dsl/mcp" "github.com/yaoapp/yao/dsl/mcp"
"github.com/yaoapp/yao/dsl/model" "github.com/yaoapp/yao/dsl/model"
"github.com/yaoapp/yao/dsl/types" "github.com/yaoapp/yao/dsl/types"
@ -17,11 +18,15 @@ type DSL struct {
exts []string exts []string
root string root string
manager types.Manager manager types.Manager
db types.IO
fs types.IO
} }
// New returns a new DSL manager // New returns a new DSL manager
func New(typ types.Type) (types.DSL, error) { func New(typ types.Type) (types.DSL, error) {
var manager types.Manager var manager types.Manager
var db types.IO = io.NewDB(typ)
var fs types.IO = io.NewFS(typ)
// Get the root path and the extensions of the type // Get the root path and the extensions of the type
root, exts := types.TypeRootAndExts(typ) root, exts := types.TypeRootAndExts(typ)
@ -30,15 +35,15 @@ func New(typ types.Type) (types.DSL, error) {
switch typ { switch typ {
case types.TypeConnector: case types.TypeConnector:
exts = []string{".conn.yao", ".conn.jsonc", ".conn.json"} exts = []string{".conn.yao", ".conn.jsonc", ".conn.json"}
manager = connector.New(root) manager = connector.New(root, fs, db)
case types.TypeModel: case types.TypeModel:
exts = []string{".mod.yao", ".mod.jsonc", ".mod.json"} exts = []string{".mod.yao", ".mod.jsonc", ".mod.json"}
manager = model.New(root) manager = model.New(root, fs, db)
case types.TypeMCPClient: case types.TypeMCPClient:
exts = []string{".mcp.yao", ".mcp.jsonc", ".mcp.json"} exts = []string{".mcp.yao", ".mcp.jsonc", ".mcp.json"}
manager = mcp.NewClient(root) manager = mcp.NewClient(root, fs, db)
// case types.TypeMCPServer: // case types.TypeMCPServer:
// exts = []string{".mcp.yao", ".mcp.jsonc", ".mcp.json"} // exts = []string{".mcp.yao", ".mcp.jsonc", ".mcp.json"}
@ -46,27 +51,27 @@ func New(typ types.Type) (types.DSL, error) {
case types.TypeAPI: case types.TypeAPI:
exts = []string{".http.yao", ".http.jsonc", ".http.json"} exts = []string{".http.yao", ".http.jsonc", ".http.json"}
manager = api.New(root) manager = api.New(root, fs, db)
default: default:
return nil, fmt.Errorf("dsl manager is not initialized, %s not supported", typ) return nil, fmt.Errorf("dsl manager is not initialized, %s not supported", typ)
} }
return &DSL{Type: typ, manager: manager, root: root, exts: exts}, nil return &DSL{Type: typ, manager: manager, root: root, exts: exts, db: db, fs: fs}, nil
} }
// Inspect DSL // Inspect DSL
func (dsl *DSL) Inspect(ctx context.Context, id string) (*types.Info, error) { func (dsl *DSL) Inspect(ctx context.Context, id string) (*types.Info, error) {
// Get the info from the db // Get the info from the db
info, exists, err := dsl.dbInspect(id) info, exists, err := dsl.db.Inspect(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !exists { if !exists {
// Get the info from the file // Get the info from the file
info, exists, err = dsl.fsInspect(types.ToPath(dsl.Type, id)) info, exists, err = dsl.fs.Inspect(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -99,14 +104,14 @@ func (dsl *DSL) Path(ctx context.Context, id string) (string, error) {
func (dsl *DSL) Source(ctx context.Context, id string) (string, error) { func (dsl *DSL) Source(ctx context.Context, id string) (string, error) {
// Get the source from the db // Get the source from the db
source, exists, err := dsl.dbSource(id) source, exists, err := dsl.db.Source(id)
if err != nil { if err != nil {
return "", err return "", err
} }
if !exists { if !exists {
// Get the source from the file // Get the source from the file
source, exists, err = dsl.fsSource(types.ToPath(dsl.Type, id)) source, exists, err = dsl.fs.Source(id)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -122,13 +127,13 @@ func (dsl *DSL) Source(ctx context.Context, id string) (string, error) {
// List DSLs // List DSLs
func (dsl *DSL) List(ctx context.Context, opts *types.ListOptions) ([]*types.Info, error) { func (dsl *DSL) List(ctx context.Context, opts *types.ListOptions) ([]*types.Info, error) {
// Get the list from the db // Get the list from the db
dbList, err := dsl.dbList(opts) dbList, err := dsl.db.List(opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get the list from the file // Get the list from the file
fileList, err := dsl.fsList(opts) fileList, err := dsl.fs.List(opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -167,22 +172,35 @@ func (dsl *DSL) List(ctx context.Context, opts *types.ListOptions) ([]*types.Inf
// Create DSL // Create DSL
func (dsl *DSL) Create(ctx context.Context, options *types.CreateOptions) error { func (dsl *DSL) Create(ctx context.Context, options *types.CreateOptions) error {
if options == nil {
return fmt.Errorf("create options is required")
}
if options.Store == types.StoreTypeDB { if options.Store == types.StoreTypeDB {
err := dsl.dbCreate(options) err := dsl.db.Create(options)
if err != nil { if err != nil {
return err return err
} }
} }
if options.Store == types.StoreTypeFile { if options.Store == types.StoreTypeFile {
err := dsl.fsCreate(options) err := dsl.fs.Create(options)
if err != nil { if err != nil {
return err return err
} }
} }
var loadOptions *types.LoadOptions = &types.LoadOptions{
ID: options.ID,
Path: types.ToPath(dsl.Type, options.ID),
Source: options.Source,
Store: options.Store,
Options: options.Load,
}
// Load the DSL // Load the DSL
err := dsl.Load(ctx, options.ID, options.LoadOptions) err := dsl.Load(ctx, loadOptions)
if err != nil { if err != nil {
return err return err
} }
@ -193,7 +211,7 @@ func (dsl *DSL) Create(ctx context.Context, options *types.CreateOptions) error
// Exists Check if the DSL exists // Exists Check if the DSL exists
func (dsl *DSL) Exists(ctx context.Context, id string) (bool, error) { func (dsl *DSL) Exists(ctx context.Context, id string) (bool, error) {
// Check if the DSL exists in the db // Check if the DSL exists in the db
exists, err := dsl.dbExists(id) exists, err := dsl.db.Exists(id)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -203,20 +221,24 @@ func (dsl *DSL) Exists(ctx context.Context, id string) (bool, error) {
} }
// Check if the DSL exists in the file // Check if the DSL exists in the file
return dsl.fsExists(id) return dsl.fs.Exists(id)
} }
// Update DSL // Update DSL
func (dsl *DSL) Update(ctx context.Context, options *types.UpdateOptions) error { func (dsl *DSL) Update(ctx context.Context, options *types.UpdateOptions) error {
if options == nil {
return fmt.Errorf("update options is required")
}
// Exists // Exists
info, exists, err := dsl.dbInspect(options.ID) info, exists, err := dsl.db.Inspect(options.ID)
if err != nil { if err != nil {
return err return err
} }
if !exists { if !exists {
info, exists, err = dsl.fsInspect(types.ToPath(dsl.Type, options.ID)) info, exists, err = dsl.fs.Inspect(options.ID)
if err != nil { if err != nil {
return err return err
} }
@ -225,92 +247,113 @@ func (dsl *DSL) Update(ctx context.Context, options *types.UpdateOptions) error
} }
} }
// Create the reload options
var reloadOptions *types.ReloadOptions = &types.ReloadOptions{
ID: options.ID,
Path: info.Path,
Source: options.Source,
Store: info.Store,
Options: options.Reload,
}
// Update the DSL in the db // Update the DSL in the db
if info.Store == types.StoreTypeDB { if info.Store == types.StoreTypeDB {
err := dsl.dbUpdate(options) err := dsl.db.Update(options)
if err != nil { if err != nil {
return err return err
} }
// Reload the DSL // Reload the DSL
return dsl.manager.Reload(ctx, options.ID, options.ReloadOptions) return dsl.manager.Reload(ctx, reloadOptions)
} }
// Update the DSL in the file // Update the DSL in the file
err = dsl.fsUpdate(options) err = dsl.fs.Update(options)
if err != nil { if err != nil {
return err return err
} }
// Reload the DSL // Reload the DSL
return dsl.manager.Reload(ctx, options.ID, options.ReloadOptions) return dsl.manager.Reload(ctx, reloadOptions)
} }
// Delete DSL // Delete DSL
func (dsl *DSL) Delete(ctx context.Context, id string, options ...interface{}) error { func (dsl *DSL) Delete(ctx context.Context, options *types.DeleteOptions) error {
if options == nil {
return fmt.Errorf("delete options is required")
}
if options.ID == "" {
return fmt.Errorf("delete options id is required")
}
// Exists // Exists
info, exists, err := dsl.dbInspect(id) info, exists, err := dsl.db.Inspect(options.ID)
if err != nil { if err != nil {
return err return err
} }
if !exists { if !exists {
info, exists, err = dsl.fsInspect(types.ToPath(dsl.Type, id)) info, exists, err = dsl.fs.Inspect(options.ID)
if err != nil { if err != nil {
return err return err
} }
if !exists { if !exists {
return fmt.Errorf("%s DSL not found, %s", dsl.Type, id) return fmt.Errorf("%s DSL not found, %s", dsl.Type, options.ID)
} }
} }
var unloadOptions interface{} var opts map[string]interface{}
if len(options) > 0 { if options.Options != nil {
unloadOptions = options[0] opts = options.Options
}
var unloadOptions *types.UnloadOptions = &types.UnloadOptions{
ID: options.ID,
Path: info.Path,
Store: info.Store,
Options: opts,
} }
if info.Store == types.StoreTypeDB { if info.Store == types.StoreTypeDB {
err = dsl.dbDelete(id) err = dsl.db.Delete(options.ID)
if err != nil { if err != nil {
return err return err
} }
// Unload the DSL // Unload the DSL
return dsl.manager.Unload(ctx, id, unloadOptions) return dsl.manager.Unload(ctx, unloadOptions)
} }
err = dsl.fsDelete(id) err = dsl.fs.Delete(options.ID)
if err != nil { if err != nil {
return err return err
} }
// Unload the DSL // Unload the DSL
return dsl.manager.Unload(ctx, id, unloadOptions) return dsl.manager.Unload(ctx, unloadOptions)
} }
// Load DSL // Load DSL
func (dsl *DSL) Load(ctx context.Context, id string, options interface{}) error { func (dsl *DSL) Load(ctx context.Context, options *types.LoadOptions) error {
return dsl.manager.Load(ctx, id, options) return dsl.manager.Load(ctx, options)
} }
// Unload DSL // Unload DSL
func (dsl *DSL) Unload(ctx context.Context, id string, options ...interface{}) error { func (dsl *DSL) Unload(ctx context.Context, options *types.UnloadOptions) error {
var unloadOptions interface{} return dsl.manager.Unload(ctx, options)
if len(options) > 0 {
unloadOptions = options[0]
}
return dsl.manager.Unload(ctx, id, unloadOptions)
} }
// Reload DSL // Reload DSL
func (dsl *DSL) Reload(ctx context.Context, id string, options interface{}) error { func (dsl *DSL) Reload(ctx context.Context, options *types.ReloadOptions) error {
return dsl.manager.Reload(ctx, id, options) return dsl.manager.Reload(ctx, options)
} }
// Execute DSL (Some DSLs can be executed) // Execute DSL (Some DSLs can be executed)
func (dsl *DSL) Execute(ctx context.Context, method string, args ...any) (any, error) { func (dsl *DSL) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return dsl.manager.Execute(ctx, method, args...) return dsl.manager.Execute(ctx, id, method, args...)
} }
// Validate DSL // Validate DSL

View file

@ -1,4 +1,4 @@
package dsl package io
import ( import (
"fmt" "fmt"
@ -10,8 +10,18 @@ import (
"github.com/yaoapp/yao/dsl/types" "github.com/yaoapp/yao/dsl/types"
) )
// getInfoFromDB get the info from the db // DB is the db io
func (dsl *DSL) dbInspect(id string) (*types.Info, bool, error) { type DB struct {
Type types.Type
}
// NewDB create a new db io
func NewDB(typ types.Type) types.IO {
return &DB{Type: typ}
}
// Inspect get the info from the db
func (db *DB) Inspect(id string) (*types.Info, bool, error) {
// Get from database // Get from database
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")
@ -57,8 +67,8 @@ func (dsl *DSL) dbInspect(id string) (*types.Info, bool, error) {
return &info, true, nil return &info, true, nil
} }
// getSourceFromDB get the source from the db // Source get the source from the db
func (dsl *DSL) dbSource(id string) (string, bool, error) { func (db *DB) Source(id string) (string, bool, error) {
// Get from database // Get from database
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")
@ -79,14 +89,14 @@ func (dsl *DSL) dbSource(id string) (string, bool, error) {
source, ok := rows[0]["source"].(string) source, ok := rows[0]["source"].(string)
if !ok { if !ok {
return "", true, fmt.Errorf("%s %s source is not a string", dsl.Type, id) return "", true, fmt.Errorf("%s %s source is not a string", db.Type, id)
} }
return source, true, nil return source, true, nil
} }
// getListFromDB get the list from the db // List get the list from the db
func (dsl *DSL) dbList(options *types.ListOptions) ([]*types.Info, error) { func (db *DB) List(options *types.ListOptions) ([]*types.Info, error) {
// Get from database // Get from database
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")
@ -96,7 +106,7 @@ func (dsl *DSL) dbList(options *types.ListOptions) ([]*types.Info, error) {
orders = []model.QueryOrder{{Column: "sort", Option: "asc"}} orders = []model.QueryOrder{{Column: "sort", Option: "asc"}}
} }
var wheres []model.QueryWhere = []model.QueryWhere{{Column: "type", Value: dsl.Type}} var wheres []model.QueryWhere = []model.QueryWhere{{Column: "type", Value: db.Type}}
// Filter by tags // Filter by tags
if len(options.Tags) > 0 { if len(options.Tags) > 0 {
@ -110,7 +120,7 @@ func (dsl *DSL) dbList(options *types.ListOptions) ([]*types.Info, error) {
// Get the list // Get the list
rows, err := m.Get(model.QueryParam{ rows, err := m.Get(model.QueryParam{
Wheres: []model.QueryWhere{{Column: "type", Value: dsl.Type}}, Wheres: []model.QueryWhere{{Column: "type", Value: db.Type}},
Select: []interface{}{"dsl_id", "label", "path", "sort", "tags", "description", "status", "store", "mtime", "ctime"}, Select: []interface{}{"dsl_id", "label", "path", "sort", "tags", "description", "status", "store", "mtime", "ctime"},
Orders: orders, Orders: orders,
}) })
@ -136,10 +146,11 @@ func (dsl *DSL) dbList(options *types.ListOptions) ([]*types.Info, error) {
return infos, nil return infos, nil
} }
func (dsl *DSL) dbCreate(options *types.CreateOptions) error { // Create create the dsl
func (db *DB) Create(options *types.CreateOptions) error {
if options.Source == "" { if options.Source == "" {
return fmt.Errorf("%s %s source is required", dsl.Type, options.ID) return fmt.Errorf("%s %s source is required", db.Type, options.ID)
} }
// Get info from source // Get info from source
@ -154,7 +165,7 @@ func (dsl *DSL) dbCreate(options *types.CreateOptions) error {
data := map[string]interface{}{ data := map[string]interface{}{
"source": options.Source, "source": options.Source,
"dsl_id": options.ID, "dsl_id": options.ID,
"type": dsl.Type, "type": db.Type,
"label": info.Label, "label": info.Label,
"path": info.Path, "path": info.Path,
"sort": info.Sort, "sort": info.Sort,
@ -174,9 +185,10 @@ func (dsl *DSL) dbCreate(options *types.CreateOptions) error {
return nil return nil
} }
func (dsl *DSL) dbUpdate(options *types.UpdateOptions) error { // Update update the dsl
func (db *DB) Update(options *types.UpdateOptions) error {
if options.Source == "" && options.Info == nil { if options.Source == "" && options.Info == nil {
return fmt.Errorf("%s %s one of source or info is required", dsl.Type, options.ID) return fmt.Errorf("%s %s one of source or info is required", db.Type, options.ID)
} }
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")
@ -192,7 +204,7 @@ func (dsl *DSL) dbUpdate(options *types.UpdateOptions) error {
} }
if len(rows) == 0 { if len(rows) == 0 {
return fmt.Errorf("%s %s not found", dsl.Type, options.ID) return fmt.Errorf("%s %s not found", db.Type, options.ID)
} }
row := rows[0] row := rows[0]
@ -234,7 +246,8 @@ func (dsl *DSL) dbUpdate(options *types.UpdateOptions) error {
return nil return nil
} }
func (dsl *DSL) dbDelete(id string) error { // Delete delete the dsl
func (db *DB) Delete(id string) error {
// Get from database // Get from database
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")
@ -250,7 +263,7 @@ func (dsl *DSL) dbDelete(id string) error {
} }
if len(rows) == 0 { if len(rows) == 0 {
return fmt.Errorf("%s %s not found", dsl.Type, id) return fmt.Errorf("%s %s not found", db.Type, id)
} }
// Delete the dsl // Delete the dsl
@ -258,7 +271,8 @@ func (dsl *DSL) dbDelete(id string) error {
return m.Delete(row["id"]) return m.Delete(row["id"])
} }
func (dsl *DSL) dbExists(id string) (bool, error) { // Exists check if the dsl exists
func (db *DB) Exists(id string) (bool, error) {
// Get from database // Get from database
m := model.Select("__yao.dsl") m := model.Select("__yao.dsl")

View file

@ -1,4 +1,4 @@
package dsl package io
import ( import (
"fmt" "fmt"
@ -8,15 +8,19 @@ import (
"github.com/yaoapp/yao/dsl/types" "github.com/yaoapp/yao/dsl/types"
) )
// getInfoFromFile get the info from the file // FS is the fs io
func (dsl *DSL) fsInspect(id string, path ...string) (*types.Info, bool, error) { type FS struct {
file := "" Type types.Type
if len(path) > 0 {
file = path[0]
} else {
file = types.ToPath(dsl.Type, id)
} }
// NewFS create a new fs io
func NewFS(typ types.Type) types.IO {
return &FS{Type: typ}
}
// Inspect get the info from the file
func (fs *FS) Inspect(id string) (*types.Info, bool, error) {
file := types.ToPath(fs.Type, id)
var info types.Info = types.Info{ID: id, Path: file} var info types.Info = types.Info{ID: id, Path: file}
exists, err := application.App.Exists(file) exists, err := application.App.Exists(file)
if err != nil { if err != nil {
@ -49,9 +53,9 @@ func (dsl *DSL) fsInspect(id string, path ...string) (*types.Info, bool, error)
return &info, true, nil return &info, true, nil
} }
// getSourceFromFile get the source from the file // Source get the source from the file
func (dsl *DSL) fsSource(id string) (string, bool, error) { func (fs *FS) Source(id string) (string, bool, error) {
path := types.ToPath(dsl.Type, id) path := types.ToPath(fs.Type, id)
exists, err := application.App.Exists(path) exists, err := application.App.Exists(path)
if err != nil { if err != nil {
return "", false, err return "", false, err
@ -68,9 +72,9 @@ func (dsl *DSL) fsSource(id string) (string, bool, error) {
return string(data), true, nil return string(data), true, nil
} }
// getListFromPath get the list from the path // List get the list from the path
func (dsl *DSL) fsList(options *types.ListOptions) ([]*types.Info, error) { func (fs *FS) List(options *types.ListOptions) ([]*types.Info, error) {
root, exts := types.TypeRootAndExts(dsl.Type) root, exts := types.TypeRootAndExts(fs.Type)
var infos []*types.Info = []*types.Info{} var infos []*types.Info = []*types.Info{}
patterns := []string{} patterns := []string{}
for _, ext := range exts { for _, ext := range exts {
@ -81,8 +85,8 @@ func (dsl *DSL) fsList(options *types.ListOptions) ([]*types.Info, error) {
if isdir { if isdir {
return nil return nil
} }
id := types.WithTypeToID(dsl.Type, file) id := types.WithTypeToID(fs.Type, file)
info, _, err := dsl.fsInspect(id, file) info, _, err := fs.Inspect(id)
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
return nil return nil
@ -112,9 +116,10 @@ func (dsl *DSL) fsList(options *types.ListOptions) ([]*types.Info, error) {
return infos, err return infos, err
} }
func (dsl *DSL) fsCreate(options *types.CreateOptions) error { // Create create the file
func (fs *FS) Create(options *types.CreateOptions) error {
path := types.ToPath(dsl.Type, options.ID) path := types.ToPath(fs.Type, options.ID)
// Check if the file is a directory // Check if the file is a directory
exists, err := application.App.Exists(path) exists, err := application.App.Exists(path)
@ -123,21 +128,22 @@ func (dsl *DSL) fsCreate(options *types.CreateOptions) error {
} }
if exists { if exists {
return fmt.Errorf("%v %s already exists", dsl.Type, options.ID) return fmt.Errorf("%v %s already exists", fs.Type, options.ID)
} }
// Create the file // Create the file
return application.App.Write(path, []byte(options.Source)) return application.App.Write(path, []byte(options.Source))
} }
func (dsl *DSL) fsUpdate(options *types.UpdateOptions) error { // Update update the file
func (fs *FS) Update(options *types.UpdateOptions) error {
// Validate the options // Validate the options
if options.Source == "" && options.Info == nil { if options.Source == "" && options.Info == nil {
return fmt.Errorf("%v %s one of source or info is required", dsl.Type, options.ID) return fmt.Errorf("%v %s one of source or info is required", fs.Type, options.ID)
} }
path := types.ToPath(dsl.Type, options.ID) path := types.ToPath(fs.Type, options.ID)
// Check if the file exists // Check if the file exists
exists, err := application.App.Exists(path) exists, err := application.App.Exists(path)
@ -146,7 +152,7 @@ func (dsl *DSL) fsUpdate(options *types.UpdateOptions) error {
} }
if !exists { if !exists {
return fmt.Errorf("%v %s not found", dsl.Type, options.ID) return fmt.Errorf("%v %s not found", fs.Type, options.ID)
} }
// Update source // Update source
@ -179,9 +185,10 @@ func (dsl *DSL) fsUpdate(options *types.UpdateOptions) error {
return application.App.Write(path, []byte(new)) return application.App.Write(path, []byte(new))
} }
func (dsl *DSL) fsDelete(id string) error { // Delete delete the file
func (fs *FS) Delete(id string) error {
path := types.ToPath(dsl.Type, id) path := types.ToPath(fs.Type, id)
// Check if the file is a directory // Check if the file is a directory
exists, err := application.App.Exists(path) exists, err := application.App.Exists(path)
@ -190,14 +197,15 @@ func (dsl *DSL) fsDelete(id string) error {
} }
if !exists { if !exists {
return fmt.Errorf("%v %s not found", dsl.Type, id) return fmt.Errorf("%v %s not found", fs.Type, id)
} }
// Delete the file // Delete the file
return application.App.Remove(path) return application.App.Remove(path)
} }
func (dsl *DSL) fsExists(id string) (bool, error) { // Exists check if the file exists
path := types.ToPath(dsl.Type, id) func (fs *FS) Exists(id string) (bool, error) {
path := types.ToPath(fs.Type, id)
return application.App.Exists(path) return application.App.Exists(path)
} }

View file

@ -9,16 +9,13 @@ import (
// YaoMCPClient is the MCP client DSL manager // YaoMCPClient is the MCP client DSL manager
type YaoMCPClient struct { type YaoMCPClient struct {
root string // The relative path of the MCP client DSL root string // The relative path of the MCP client DSL
fs types.IO // The file system IO interface
db types.IO // The database IO interface
} }
// NewClient returns a new MCP client DSL manager // NewClient returns a new MCP client DSL manager
func NewClient(root string) types.Manager { func NewClient(root string, fs types.IO, db types.IO) types.Manager {
return New(root) return &YaoMCPClient{root: root, fs: fs, db: db}
}
// New returns a new connector DSL manager
func New(root string) types.Manager {
return &YaoMCPClient{root: root}
} }
// Loaded return all loaded DSLs // Loaded return all loaded DSLs
@ -27,17 +24,17 @@ func (client *YaoMCPClient) Loaded(ctx context.Context) (map[string]*types.Info,
} }
// Load will unload the DSL first, then load the DSL from DB or file system // Load will unload the DSL first, then load the DSL from DB or file system
func (client *YaoMCPClient) Load(ctx context.Context, id string, options interface{}) error { func (client *YaoMCPClient) Load(ctx context.Context, options *types.LoadOptions) error {
return nil return nil
} }
// Unload will unload the DSL from memory // Unload will unload the DSL from memory
func (client *YaoMCPClient) Unload(ctx context.Context, id string, options interface{}) error { func (client *YaoMCPClient) Unload(ctx context.Context, options *types.UnloadOptions) error {
return nil return nil
} }
// Reload will unload the DSL first, then reload the DSL from DB or file system // Reload will unload the DSL first, then reload the DSL from DB or file system
func (client *YaoMCPClient) Reload(ctx context.Context, id string, options interface{}) error { func (client *YaoMCPClient) Reload(ctx context.Context, options *types.ReloadOptions) error {
return nil return nil
} }
@ -47,6 +44,6 @@ func (client *YaoMCPClient) Validate(ctx context.Context, source string) (bool,
} }
// Execute will execute the DSL // Execute will execute the DSL
func (client *YaoMCPClient) Execute(ctx context.Context, method string, args ...any) (any, error) { func (client *YaoMCPClient) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return nil, nil return nil, nil
} }

View file

@ -22,17 +22,17 @@ func (server *YaoMCPServer) Loaded(ctx context.Context) (map[string]*types.Info,
} }
// Load will unload the DSL first, then load the DSL from DB or file system // Load will unload the DSL first, then load the DSL from DB or file system
func (server *YaoMCPServer) Load(ctx context.Context, id string, options interface{}) error { func (server *YaoMCPServer) Load(ctx context.Context, options *types.LoadOptions) error {
return nil return nil
} }
// Unload will unload the DSL from memory // Unload will unload the DSL from memory
func (server *YaoMCPServer) Unload(ctx context.Context, id string, options interface{}) error { func (server *YaoMCPServer) Unload(ctx context.Context, options *types.UnloadOptions) error {
return nil return nil
} }
// Reload will unload the DSL first, then reload the DSL from DB or file system // Reload will unload the DSL first, then reload the DSL from DB or file system
func (server *YaoMCPServer) Reload(ctx context.Context, id string, options interface{}) error { func (server *YaoMCPServer) Reload(ctx context.Context, options *types.ReloadOptions) error {
return nil return nil
} }
@ -42,6 +42,6 @@ func (server *YaoMCPServer) Validate(ctx context.Context, source string) (bool,
} }
// Execute will execute the DSL // Execute will execute the DSL
func (server *YaoMCPServer) Execute(ctx context.Context, method string, args ...any) (any, error) { func (server *YaoMCPServer) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return nil, nil return nil, nil
} }

View file

@ -10,17 +10,14 @@ import (
// YaoModel is the MCP client DSL manager // YaoModel is the MCP client DSL manager
type YaoModel struct { type YaoModel struct {
root string // The relative path of the MCP client DSL root string // The relative path of the model DSL
} fs types.IO // The file system IO interface
db types.IO // The database IO interface
// NewClient returns a new MCP client DSL manager
func NewClient(root string) types.Manager {
return New(root)
} }
// New returns a new connector DSL manager // New returns a new connector DSL manager
func New(root string) types.Manager { func New(root string, fs types.IO, db types.IO) types.Manager {
return &YaoModel{root: root} return &YaoModel{root: root, fs: fs, db: db}
} }
// Loaded return all loaded DSLs // Loaded return all loaded DSLs
@ -43,10 +40,19 @@ func (m *YaoModel) Loaded(ctx context.Context) (map[string]*types.Info, error) {
} }
// Load will unload the DSL first, then load the DSL from DB or file system // Load will unload the DSL first, then load the DSL from DB or file system
func (m *YaoModel) Load(ctx context.Context, id string, options interface{}) error { func (m *YaoModel) Load(ctx context.Context, options *types.LoadOptions) error {
if options == nil {
return fmt.Errorf("load options is required")
}
if options.ID == "" {
return fmt.Errorf("load options id is required")
}
var opts map[string]interface{} var opts map[string]interface{}
if v, ok := options.(map[string]interface{}); ok { if options.Options != nil {
opts = v opts = options.Options
} }
var migration bool = false var migration bool = false
@ -59,8 +65,8 @@ func (m *YaoModel) Load(ctx context.Context, id string, options interface{}) err
reset = v.(bool) reset = v.(bool)
} }
path := types.ToPath(types.TypeModel, id) path := types.ToPath(types.TypeModel, options.ID)
mod, err := model.LoadSync(path, id) mod, err := model.LoadSync(path, options.ID)
if err != nil { if err != nil {
return err return err
} }
@ -73,11 +79,19 @@ func (m *YaoModel) Load(ctx context.Context, id string, options interface{}) err
} }
// Unload will unload the DSL from memory // Unload will unload the DSL from memory
func (m *YaoModel) Unload(ctx context.Context, id string, options interface{}) error { func (m *YaoModel) Unload(ctx context.Context, options *types.UnloadOptions) error {
if options == nil {
return fmt.Errorf("unload options is required")
}
if options.ID == "" {
return fmt.Errorf("unload options id is required")
}
var opts map[string]interface{} var opts map[string]interface{}
if v, ok := options.(map[string]interface{}); ok { if options.Options != nil {
opts = v opts = options.Options
} }
var dropTable bool = false var dropTable bool = false
@ -85,9 +99,9 @@ func (m *YaoModel) Unload(ctx context.Context, id string, options interface{}) e
dropTable = v.(bool) dropTable = v.(bool)
} }
mod := model.Select(id) mod := model.Select(options.ID)
if mod == nil { if mod == nil {
return fmt.Errorf("model %s not found", id) return fmt.Errorf("model %s not found", options.ID)
} }
if dropTable { if dropTable {
@ -98,11 +112,19 @@ func (m *YaoModel) Unload(ctx context.Context, id string, options interface{}) e
} }
// Reload will unload the DSL first, then reload the DSL from DB or file system // Reload will unload the DSL first, then reload the DSL from DB or file system
func (m *YaoModel) Reload(ctx context.Context, id string, options interface{}) error { func (m *YaoModel) Reload(ctx context.Context, options *types.ReloadOptions) error {
if options == nil {
return fmt.Errorf("reload options is required")
}
if options.ID == "" {
return fmt.Errorf("reload options id is required")
}
var opts map[string]interface{} var opts map[string]interface{}
if v, ok := options.(map[string]interface{}); ok { if options.Options != nil {
opts = v opts = options.Options
} }
var migration bool = false var migration bool = false
@ -116,8 +138,8 @@ func (m *YaoModel) Reload(ctx context.Context, id string, options interface{}) e
} }
// Reload the model // Reload the model
path := types.ToPath(types.TypeModel, id) path := types.ToPath(types.TypeModel, options.ID)
mod, err := model.LoadSync(path, id) mod, err := model.LoadSync(path, options.ID)
if err != nil { if err != nil {
return err return err
} }
@ -134,6 +156,6 @@ func (m *YaoModel) Validate(ctx context.Context, source string) (bool, []types.L
} }
// Execute will execute the DSL // Execute will execute the DSL
func (m *YaoModel) Execute(ctx context.Context, method string, args ...any) (any, error) { func (m *YaoModel) Execute(ctx context.Context, id string, method string, args ...any) (any, error) {
return nil, fmt.Errorf("Not implemented") return nil, fmt.Errorf("Not implemented")
} }

View file

@ -1,6 +1,8 @@
package types package types
import "context" import (
"context"
)
// DSL interface // DSL interface
type DSL interface { type DSL interface {
@ -13,15 +15,15 @@ type DSL interface {
// DSL Operations // DSL Operations
Create(ctx context.Context, options *CreateOptions) error // Create DSL, Create will unload the DSL first, then create the DSL to DB Create(ctx context.Context, options *CreateOptions) error // Create DSL, Create will unload the DSL first, then create the DSL to DB
Update(ctx context.Context, options *UpdateOptions) error // Update DSL, Update will unload the DSL first, then update the DSL, if update info only, will not unload the DSL Update(ctx context.Context, options *UpdateOptions) error // Update DSL, Update will unload the DSL first, then update the DSL, if update info only, will not unload the DSL
Delete(ctx context.Context, id string, unloadOptions ...interface{}) error // Delete DSL, Delete will unload the DSL first, then delete the DSL file Delete(ctx context.Context, options *DeleteOptions) error // Delete DSL, Delete will unload the DSL first, then delete the DSL file
// Load manager // Load manager
Load(ctx context.Context, id string, options interface{}) error // Load DSL, Load will unload the DSL first, then load the DSL from DB or file system Load(ctx context.Context, options *LoadOptions) error // Load DSL, Load will unload the DSL first, then load the DSL from DB or file system
Reload(ctx context.Context, id string, options interface{}) error // Reload DSL, Reload will unload the DSL first, then reload the DSL from DB or file system Reload(ctx context.Context, options *ReloadOptions) error // Reload DSL, Reload will unload the DSL first, then reload the DSL from DB or file system
Unload(ctx context.Context, id string, options ...interface{}) error // Unload DSL, Unload will unload the DSL from memory Unload(ctx context.Context, options *UnloadOptions) error // Unload DSL, Unload will unload the DSL from memory
// Execute // Execute
Execute(ctx context.Context, method string, args ...any) (any, error) // Execute DSL (Some DSLs can be executed) Execute(ctx context.Context, id string, method string, args ...any) (any, error) // Execute DSL (Some DSLs can be executed)
// Validate // Validate
Validate(ctx context.Context, source string) (bool, []LintMessage) // Validate DSL, Validate will validate the DSL from source Validate(ctx context.Context, source string) (bool, []LintMessage) // Validate DSL, Validate will validate the DSL from source
@ -33,17 +35,28 @@ type Manager interface {
Loaded(ctx context.Context) (map[string]*Info, error) // Get all loaded DSLs Loaded(ctx context.Context) (map[string]*Info, error) // Get all loaded DSLs
// Load DSL, Load will unload the DSL first, then load the DSL from DB or file system // Load DSL, Load will unload the DSL first, then load the DSL from DB or file system
Load(ctx context.Context, id string, options interface{}) error Load(ctx context.Context, options *LoadOptions) error
// Unload DSL, Unload will unload the DSL from memory // Unload DSL, Unload will unload the DSL from memory
Unload(ctx context.Context, id string, options interface{}) error Unload(ctx context.Context, options *UnloadOptions) error
// Reload DSL, Reload will unload the DSL first, then reload the DSL from DB or file system // Reload DSL, Reload will unload the DSL first, then reload the DSL from DB or file system
Reload(ctx context.Context, id string, options interface{}) error Reload(ctx context.Context, options *ReloadOptions) error
// Validate DSL, Validate will validate the DSL from source // Validate DSL, Validate will validate the DSL from source
Validate(ctx context.Context, source string) (bool, []LintMessage) Validate(ctx context.Context, source string) (bool, []LintMessage)
// Execute DSL (Some DSLs can be executed) // Execute DSL (Some DSLs can be executed)
Execute(ctx context.Context, method string, args ...any) (any, error) Execute(ctx context.Context, id string, method string, args ...any) (any, error)
}
// IO interface
type IO interface {
Inspect(id string) (*Info, bool, error)
Source(id string) (string, bool, error)
List(options *ListOptions) ([]*Info, error)
Create(options *CreateOptions) error
Update(options *UpdateOptions) error
Delete(id string) error
Exists(id string) (bool, error)
} }

View file

@ -79,14 +79,20 @@ const (
// Info for DSL // Info for DSL
type Info struct { type Info struct {
ID string ID string
Type Type Type Type
Sort int
Path string
Label string Label string
Description string Description string
Tags []string Tags []string
Status Status
Sort int
Path string
Store StoreType Store StoreType
Readable bool
Builtin bool
Status Status
Mtime time.Time Mtime time.Time
Ctime time.Time Ctime time.Time
} }
@ -103,7 +109,7 @@ type CreateOptions struct {
ID string // ID is the id of the DSL, if not provided, a new id will be generated, required ID string // ID is the id of the DSL, if not provided, a new id will be generated, required
Source string // Source is the source of the DSL, if not provided, the DSL will be loaded from the file system Source string // Source is the source of the DSL, if not provided, the DSL will be loaded from the file system
Store StoreType // Store is the store type of the DSL, if not provided, the DSL will be loaded from the file system Store StoreType // Store is the store type of the DSL, if not provided, the DSL will be loaded from the file system
LoadOptions interface{} // LoadOptions is the options for the DSL, if not provided, the DSL will be loaded from the file system Load map[string]interface{} // LoadOptions is the options for the DSL, if not provided, the DSL will be loaded from the file system
} }
// UpdateOptions for DSL upsert // UpdateOptions for DSL upsert
@ -111,7 +117,41 @@ type UpdateOptions struct {
ID string // ID is the id of the DSL, if not provided, a new id will be generated, required ID string // ID is the id of the DSL, if not provided, a new id will be generated, required
Info *Info // Info is the info of the DSL, if not provided, the DSL will be loaded from the file system, one of info or source must be provided Info *Info // Info is the info of the DSL, if not provided, the DSL will be loaded from the file system, one of info or source must be provided
Source string // Source is the source of the DSL, if not provided, the DSL will be loaded from the file system, one of info or source must be provided Source string // Source is the source of the DSL, if not provided, the DSL will be loaded from the file system, one of info or source must be provided
ReloadOptions interface{} // ReloadOptions is the options for the DSL, if not provided, the DSL will be loaded from the file system Reload map[string]interface{} // ReloadOptions is the options for the DSL, if not provided, the DSL will be loaded from the file system
}
// DeleteOptions for DSL delete options
type DeleteOptions struct {
ID string // ID is the id of the DSL, if not provided, a new id will be generated, required
Path string // Path is the path of the DSL, if not provided, the DSL will be loaded from the file system
Options map[string]interface{} // Options is the options for the DSL, if not provided, the DSL will be loaded from the file system
}
// LoadOptions for DSL load options
type LoadOptions struct {
ID string
Path string
Source string
Store StoreType
Options map[string]interface{}
}
// UnloadOptions for DSL unload options
type UnloadOptions struct {
ID string
Path string
Source string
Store StoreType
Options map[string]interface{}
}
// ReloadOptions for DSL reload options
type ReloadOptions struct {
ID string
Path string
Source string
Store StoreType
Options map[string]interface{}
} }
// LintMessage for DSL linter // LintMessage for DSL linter