Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
|
|
|
//
|
|
|
|
|
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
//
|
|
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
package cli
|
|
|
|
|
|
2026-06-12 14:56:44 +08:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
2026-06-15 10:10:14 +08:00
|
|
|
"ragflow/internal/common"
|
2026-06-12 14:56:44 +08:00
|
|
|
"strings"
|
|
|
|
|
)
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// region AUTH commands
|
2026-03-25 21:39:14 +08:00
|
|
|
func (p *Parser) parseAdminLoginUser() (*Command, error) {
|
|
|
|
|
cmd := NewCommand("login_user")
|
|
|
|
|
|
|
|
|
|
p.nextToken() // consume LOGIN
|
2026-06-09 15:22:50 +08:00
|
|
|
if p.curToken.Type != TokenAdmin {
|
|
|
|
|
return nil, fmt.Errorf("expected ADMIN after LOGIN")
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
email, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["email"] = email
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-04-07 09:44:51 +08:00
|
|
|
// Optional: PASSWORD 'password'
|
|
|
|
|
if p.curToken.Type == TokenPassword {
|
|
|
|
|
p.nextToken()
|
2026-06-23 10:26:31 +08:00
|
|
|
var password string
|
|
|
|
|
password, err = p.parseQuotedString()
|
2026-04-07 09:44:51 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["password"] = password
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 11:54:23 +08:00
|
|
|
func (p *Parser) parseAdminLogout() (*Command, error) {
|
|
|
|
|
cmd := NewCommand("logout")
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-26 11:54:23 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
func (p *Parser) parseAdminPingServer() (*Command, error) {
|
2026-06-21 16:50:02 +08:00
|
|
|
cmd := NewCommand("ping_server")
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// endregion
|
|
|
|
|
|
|
|
|
|
// region LIST commands
|
2026-06-23 10:26:31 +08:00
|
|
|
func (p *Parser) parseAdminListCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume LIST
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenServices:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminListServices()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenUsers:
|
2026-06-18 15:21:44 +08:00
|
|
|
return p.parseAdminListUsersCommand()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenRoles:
|
2026-06-20 02:31:07 +08:00
|
|
|
return p.parseAdminListRoles()
|
|
|
|
|
case TokenResources:
|
|
|
|
|
return p.parseAdminListResources()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenVars:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminListVariables()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenConfigs:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminListConfigs()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenEnvs:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminListEnvironments()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenAvailable:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseListAvailableProviders()
|
2026-06-21 16:50:02 +08:00
|
|
|
case TokenProvider:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminListProviderModels()
|
2026-06-23 10:26:31 +08:00
|
|
|
case TokenProviders:
|
|
|
|
|
return p.parseAdminListProviders()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenModels:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminListModels()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenUser:
|
|
|
|
|
return p.parseAdminListUserCommand()
|
2026-05-25 14:00:08 +08:00
|
|
|
case TokenIngestors:
|
|
|
|
|
return p.parseAdminListIngestors()
|
|
|
|
|
case TokenIngestion:
|
|
|
|
|
return p.parseAdminListIngestionTasks()
|
2026-06-09 15:22:50 +08:00
|
|
|
case TokenAPI:
|
|
|
|
|
return p.parseListApiCommand()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown LIST target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
func (p *Parser) parseAdminListServices() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume SERVICES
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
return NewCommand("admin_list_services"), nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
func (p *Parser) parseAdminListRoles() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ROLES
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return NewCommand("admin_list_roles_command"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminListResources() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume RESOURCES
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return NewCommand("admin_list_resources_command"), nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
func (p *Parser) parseAdminListVariables() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume VARIABLES
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return NewCommand("admin_list_variables"), nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminListConfigs() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume CONFIGS
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-22 08:19:23 +08:00
|
|
|
return NewCommand("admin_list_configs"), nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminListEnvironments() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ENVIRONMENTS
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-22 08:19:23 +08:00
|
|
|
return NewCommand("admin_list_environments"), nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseListAvailableProviders() (*Command, error) {
|
2026-03-31 18:42:12 +08:00
|
|
|
p.nextToken() // consume AVAILABLE
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenProviders {
|
|
|
|
|
return nil, fmt.Errorf("expected PROVIDERS")
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
return NewCommand("admin_list_available_providers"), nil
|
Refactor Go server model provider reading and access (#13831)
### What problem does this PR solve?
1. Refactor model provider json file format
2. Use memory data structure to replace database
3. Add CLI command to access
```
RAGFlow(user)> list pool models from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
| map[] | 256000 | [llm] | grok-4 |
| map[] | 131072 | [llm] | grok-3 |
| map[] | 131072 | [llm] | grok-3-fast |
| map[] | 131072 | [llm] | grok-3-mini |
| map[] | 131072 | [llm] | grok-3-mini-mini-fast |
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+-----------------------+
RAGFlow(user)> show pool model 'grok-2-vision' from 'xai';
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| features | max_tokens | model_types | name |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
| map[multimodal:map[enabled:true input_modalities:[image] output_modalities:[text]]] | 32768 | [vlm] | grok-2-vision |
+-------------------------------------------------------------------------------------+------------+-------------+---------------+
RAGFlow(user)> list pool providers;
+--------+------------------------------------------------------------+---------------------------+
| name | tags | url |
+--------+------------------------------------------------------------+---------------------------+
| OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | https://api.openai.com/v1 |
| xAI | LLM | https://api.x.ai/v1 |
+--------+------------------------------------------------------------+---------------------------+
RAGFlow(user)> show pool provider 'openai';
+---------------------------+--------+------------------------------------------------------------+--------------+
| base_url | name | tags | total_models |
+---------------------------+--------+------------------------------------------------------------+--------------+
| https://api.openai.com/v1 | OpenAI | LLM,TEXT EMBEDDING,TTS,TEXT RE-RANK,SPEECH2TEXT,MODERATION | 27 |
+---------------------------+--------+------------------------------------------------------------+--------------+
```
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- [x] Refactoring
---------
Signed-off-by: Jin Hai <haijin.chn@gmail.com>
2026-03-30 12:00:49 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
func (p *Parser) parseAdminListFiles() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume FILES
|
|
|
|
|
if p.curToken.Type != TokenOf {
|
|
|
|
|
return nil, fmt.Errorf("expected OF")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenDataset {
|
|
|
|
|
return nil, fmt.Errorf("expected DATASET")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
datasetName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("list_user_dataset_files")
|
|
|
|
|
cmd.Params["dataset_name"] = datasetName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-12 14:56:44 +08:00
|
|
|
func (p *Parser) parseAdminListIngestors() (*Command, error) {
|
2026-05-09 10:03:23 +08:00
|
|
|
p.nextToken() // consume TASKS
|
2026-06-12 14:56:44 +08:00
|
|
|
cmd := NewCommand("admin_list_ingestors")
|
|
|
|
|
|
2026-05-09 10:03:23 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 14:00:08 +08:00
|
|
|
func (p *Parser) parseAdminListIngestionTasks() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume Ingestion
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS")
|
|
|
|
|
}
|
2026-06-12 14:56:44 +08:00
|
|
|
p.nextToken() // consume TASKS
|
2026-05-25 14:00:08 +08:00
|
|
|
|
|
|
|
|
cmd := NewCommand("list_admin_ingestion_tasks")
|
2026-06-12 14:56:44 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-12 14:56:44 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 14:00:08 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// LIST PROVIDER 'provider_name' MODELS;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminListProviderModels() (*Command, error) {
|
2026-06-21 16:50:02 +08:00
|
|
|
p.nextToken() // consume PROVIDER
|
|
|
|
|
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenModels {
|
|
|
|
|
return nil, fmt.Errorf("expected MODELS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume MODELS
|
|
|
|
|
cmd := NewCommand("admin_list_provider_models")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 10:26:31 +08:00
|
|
|
// parseAdminListProviders parses LIST PROVIDERS command
|
|
|
|
|
func (p *Parser) parseAdminListProviders() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PROVIDERS
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return NewCommand("admin_list_providers"), nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
func (p *Parser) parseAdminListModels() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MODELS
|
|
|
|
|
cmd := NewCommand("admin_list_all_models")
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// endregion LIST commands
|
|
|
|
|
|
|
|
|
|
// region SHOW commands
|
|
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
func (p *Parser) parseAdminShowCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume SHOW
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenService:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowService()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenUser:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowUserCommands()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenRole:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowRole()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenVersion:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowVersion()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenVar:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowVariable()
|
2026-06-19 09:57:58 +08:00
|
|
|
case TokenCurrent:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowCurrent()
|
2026-06-20 02:31:07 +08:00
|
|
|
case TokenFingerprint:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowFingerprint()
|
2026-06-20 02:31:07 +08:00
|
|
|
case TokenLicense:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowLicense()
|
2026-03-31 18:42:12 +08:00
|
|
|
case TokenProvider:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowProvider()
|
2026-03-31 18:42:12 +08:00
|
|
|
case TokenModel:
|
2026-06-21 16:50:02 +08:00
|
|
|
return p.parseAdminShowModel()
|
2026-06-09 15:22:50 +08:00
|
|
|
case TokenAdmin:
|
|
|
|
|
return p.parseUserShowAdmin()
|
|
|
|
|
case TokenAPI:
|
|
|
|
|
return p.parseUserShowAPI()
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenUsers:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminShowUsersCommands()
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenData:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminShowData()
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenQuota:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminShowQuota()
|
2026-06-18 17:09:20 +08:00
|
|
|
case TokenTasks:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminShowTasks()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown SHOW target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
func (p *Parser) parseAdminShowService() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume SERVICE
|
2026-06-22 17:33:47 +08:00
|
|
|
serviceIndex, err := p.parseNumber()
|
2026-06-21 16:50:02 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_service")
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd.Params["service_index"] = serviceIndex
|
2026-06-21 16:50:02 +08:00
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-21 16:50:02 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com';
|
|
|
|
|
// SHOW USER 'user@example.com' ACTIVITY;
|
|
|
|
|
// SHOW USER 'user@example.com' SUMMARY;
|
|
|
|
|
// SHOW USER 'user@example.com' DATASET 'dataset_name';
|
|
|
|
|
// SHOW USER 'user@example.com' STORAGE;
|
|
|
|
|
// SHOW USER 'user@example.com' QUOTA;
|
|
|
|
|
// SHOW USER 'user@example.com' INDEX;
|
|
|
|
|
// SHOW USER 'user@example.com' PERMISSION;
|
|
|
|
|
func (p *Parser) parseAdminShowUserCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenActivity:
|
|
|
|
|
return p.parseAdminShowActivityCommand(userName)
|
|
|
|
|
case TokenSummary:
|
|
|
|
|
return p.parseAdminShowUserSummaryCommand(userName)
|
|
|
|
|
case TokenDataset:
|
|
|
|
|
return p.parseAdminShowUserDataSetCommand(userName)
|
|
|
|
|
case TokenStorage:
|
|
|
|
|
return p.parseAdminShowUserStorageCommand(userName)
|
|
|
|
|
case TokenQuota:
|
|
|
|
|
return p.parseAdminShowUserQuotaCommand(userName)
|
|
|
|
|
case TokenIndex:
|
|
|
|
|
return p.parseAdminShowUserIndexCommand(userName)
|
|
|
|
|
case TokenPermission:
|
|
|
|
|
return p.parseAdminShowUserPermissionCommand(userName)
|
|
|
|
|
default:
|
|
|
|
|
return p.parseAdminShowUser(userName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com';
|
|
|
|
|
func (p *Parser) parseAdminShowUser(userName string) (*Command, error) {
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken()
|
2026-06-21 16:50:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' ACTIVITY DAYS 30;
|
|
|
|
|
func (p *Parser) parseAdminShowActivityCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ACTIVITY
|
|
|
|
|
|
|
|
|
|
var days int
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenDays {
|
|
|
|
|
p.nextToken() // consume DAYS
|
|
|
|
|
days, err = p.parseNumber()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
if days < 1 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of DAYS")
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
p.nextToken()
|
|
|
|
|
} else {
|
|
|
|
|
days = 7
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_activity_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["days"] = days
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' SUMMARY;
|
|
|
|
|
func (p *Parser) parseAdminShowUserSummaryCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume SUMMARY
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_summary_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' DATASET 'dataset_name';
|
|
|
|
|
func (p *Parser) parseAdminShowUserDataSetCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume DATASET
|
|
|
|
|
|
|
|
|
|
var tree = false
|
|
|
|
|
var datasetName string
|
|
|
|
|
var err error
|
|
|
|
|
datasetName, err = p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
if p.curToken.Type == TokenTree {
|
|
|
|
|
tree = true
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_dataset_command")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
2026-06-21 16:50:02 +08:00
|
|
|
if datasetName != "" {
|
|
|
|
|
cmd.Params["dataset_name"] = datasetName
|
|
|
|
|
}
|
|
|
|
|
if tree {
|
|
|
|
|
cmd.Params["tree"] = true
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' STORAGE;
|
|
|
|
|
func (p *Parser) parseAdminShowUserStorageCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume STORAGE
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_storage_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' QUOTA;
|
|
|
|
|
func (p *Parser) parseAdminShowUserQuotaCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume QUOTA
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_quota_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// SHOW USER 'user@example.com' INDEX;
|
|
|
|
|
func (p *Parser) parseAdminShowUserIndexCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume INDEX
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_index_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USER 'user@example.com' PERMISSION;
|
|
|
|
|
func (p *Parser) parseAdminShowUserPermissionCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PERMISSION
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_user_permission_command")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW ROLE 'role_name';
|
2026-06-22 19:03:36 +08:00
|
|
|
// SHOW ROLE 'role_name' DEFAULT MODELS;
|
2026-06-21 16:50:02 +08:00
|
|
|
func (p *Parser) parseAdminShowRole() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume ROLE
|
2026-06-21 16:50:02 +08:00
|
|
|
|
|
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-22 17:33:47 +08:00
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
var cmd *Command
|
2026-06-22 19:03:36 +08:00
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenPermission:
|
2026-06-22 17:33:47 +08:00
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("admin_show_role_permission")
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
2026-06-22 19:03:36 +08:00
|
|
|
case TokenDefault:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenModels {
|
|
|
|
|
return nil, fmt.Errorf("expect MODELS after DEFAULT")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("admin_show_role_default_models")
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
case TokenSemicolon:
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd = NewCommand("admin_show_role")
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
2026-06-22 19:03:36 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("invalid command %s", tokenTypeToString(p.curToken.Type))
|
2026-06-22 17:33:47 +08:00
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW VERSION;
|
|
|
|
|
func (p *Parser) parseAdminShowVersion() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume VERSION
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewCommand("admin_show_version_command"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW VAR 'var_name';
|
|
|
|
|
func (p *Parser) parseAdminShowVariable() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume VAR
|
|
|
|
|
varName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_variable")
|
|
|
|
|
cmd.Params["var_name"] = varName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-21 16:50:02 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW CURRENT;
|
|
|
|
|
func (p *Parser) parseAdminShowCurrent() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume CURRENT
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewCommand("admin_show_current"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW FINGERPRINT;
|
|
|
|
|
func (p *Parser) parseAdminShowFingerprint() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume FINGERPRINT
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewCommand("admin_show_fingerprint"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW LICENSE;
|
|
|
|
|
func (p *Parser) parseAdminShowLicense() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume LICENSE
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NewCommand("admin_show_license"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW PROVIDER 'provider_name';
|
|
|
|
|
func (p *Parser) parseAdminShowProvider() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PROVIDER
|
|
|
|
|
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected provider name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenModel {
|
|
|
|
|
// SHOW PROVIDER 'provider_name' MODEL 'model_name'
|
|
|
|
|
return p.parseAdminShowProviderModel(providerName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_provider")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
2026-03-25 21:39:14 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// SHOW PROVIDER 'provider_name' MODEL 'model_name';
|
|
|
|
|
func (p *Parser) parseAdminShowProviderModel(providerName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MODEL
|
|
|
|
|
|
|
|
|
|
modelName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
2026-06-21 16:50:02 +08:00
|
|
|
return nil, fmt.Errorf("expected model name: %w", err)
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
p.nextToken() // consume model_name
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
cmd := NewCommand("admin_show_provider_model")
|
|
|
|
|
cmd.Params["model_name"] = modelName
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 16:50:02 +08:00
|
|
|
// SHOW MODEL 'model_name';
|
|
|
|
|
func (p *Parser) parseAdminShowModel() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MODEL
|
|
|
|
|
|
|
|
|
|
modelName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
2026-06-21 16:50:02 +08:00
|
|
|
return nil, fmt.Errorf("expected model name: %w", err)
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-21 16:50:02 +08:00
|
|
|
|
|
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-21 16:50:02 +08:00
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_model")
|
|
|
|
|
cmd.Params["model_name"] = modelName
|
2026-03-25 21:39:14 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
func (p *Parser) parseCommonShowPoolModel() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume POOL
|
|
|
|
|
if p.curToken.Type == TokenProvider {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd := NewCommand("show_pool_provider")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-19 09:57:58 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
} else if p.curToken.Type == TokenModel {
|
|
|
|
|
p.nextToken() // skip model
|
|
|
|
|
modelName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // skip model name
|
|
|
|
|
if p.curToken.Type != TokenFrom {
|
|
|
|
|
return nil, fmt.Errorf("expected FROM")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // skip from
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // skip provider name
|
|
|
|
|
cmd := NewCommand("show_pool_model")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["model_name"] = modelName
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-19 09:57:58 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("expected PROVIDERS or MODELS")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// endregion SHOW commands
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
// parseAdminCheck
|
|
|
|
|
func (p *Parser) parseAdminCheck() (*Command, error) {
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken() // consume CHECK
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenLicense:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminCheckLicense()
|
2026-06-20 02:31:07 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown CHECK target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminCheckLicense() (*Command, error) {
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken() // consume LICENSE
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_check_license")
|
2026-06-20 02:31:07 +08:00
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// STOP INGESTION TASKS 'task_id1 task_id2';
|
2026-06-19 09:57:58 +08:00
|
|
|
func (p *Parser) parseAdminStopIngestionTasks() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume STOP
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenIngestion:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume TASK
|
|
|
|
|
|
|
|
|
|
taskString, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tasks := strings.Split(taskString, " ")
|
|
|
|
|
p.nextToken() // consume TASK
|
|
|
|
|
|
|
|
|
|
cmd = NewCommand("admin_stop_ingestion_tasks")
|
|
|
|
|
cmd.Params["tasks"] = tasks
|
|
|
|
|
case TokenUser:
|
|
|
|
|
return p.parseAdminStopUserCommand()
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected USER or INGESTION")
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-19 09:57:58 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminRemoveIngestionTasks() (*Command, error) {
|
2026-06-22 17:33:47 +08:00
|
|
|
p.nextToken() // consume INGESTION
|
2026-06-19 09:57:58 +08:00
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume TASKS
|
|
|
|
|
|
|
|
|
|
taskString, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tasks := strings.Split(taskString, " ")
|
|
|
|
|
p.nextToken() // consume TASKS
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_remove_ingestion_tasks")
|
|
|
|
|
cmd.Params["tasks"] = tasks
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-06-19 09:57:58 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// region CREATE commands
|
2026-03-25 21:39:14 +08:00
|
|
|
func (p *Parser) parseAdminCreateCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume CREATE
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenUser:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminCreateUser()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenRole:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminCreateRole()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown CREATE target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminCreateUser() (*Command, error) {
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenQuotedString:
|
|
|
|
|
var password string
|
|
|
|
|
password, err = p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_create_user")
|
2026-06-20 02:31:07 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["password"] = password
|
|
|
|
|
cmd.Params["role"] = "user"
|
|
|
|
|
case TokenKey:
|
|
|
|
|
return p.parseAdminCreateUserAPIKeyCommand(userName)
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected password or KEY after USER, got %s", p.curToken.Value)
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
return cmd, nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
// CREATE USER 'user@example.com' KEY;
|
|
|
|
|
func (p *Parser) parseAdminCreateUserAPIKeyCommand(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume KEY
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_create_user_api_key")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminCreateRole() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume ROLE
|
2026-06-20 02:31:07 +08:00
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_create_role")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type == TokenDescription {
|
|
|
|
|
p.nextToken()
|
2026-06-20 02:31:07 +08:00
|
|
|
var description string
|
|
|
|
|
description, err = p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["description"] = description
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// endregion CREATE commands
|
|
|
|
|
|
|
|
|
|
// region DROP commands
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminDropCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume DROP
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenUser:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminDropUser()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenRole:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminDropRole()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown DROP target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminDropUser() (*Command, error) {
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken() // consume USER
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
if p.curToken.Type != TokenQuotedString {
|
|
|
|
|
return nil, fmt.Errorf("expected USER name, got %s", p.curToken.Value)
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-20 02:31:07 +08:00
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenKey:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminDropUserAPIKey(userName)
|
2026-06-20 02:31:07 +08:00
|
|
|
default:
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-20 02:31:07 +08:00
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_drop_user")
|
2026-06-20 02:31:07 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
2026-03-25 21:39:14 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminDropUserAPIKey(userName string) (*Command, error) {
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken() // consume KEY
|
|
|
|
|
|
|
|
|
|
apiKey, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
2026-06-20 02:31:07 +08:00
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_drop_user_api_key")
|
2026-06-20 02:31:07 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["api_key"] = apiKey
|
|
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminDropRole() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume ROLE
|
2026-06-22 08:19:23 +08:00
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_drop_role")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminDropDataset() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume DATASET
|
|
|
|
|
datasetName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("drop_user_dataset")
|
|
|
|
|
cmd.Params["dataset_name"] = datasetName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminDropChat() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume CHAT
|
|
|
|
|
chatName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("drop_user_chat")
|
|
|
|
|
cmd.Params["chat_name"] = chatName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// endregion DROP commands
|
|
|
|
|
|
|
|
|
|
// region ALTER commands
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminAlterCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume ALTER
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenUser:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminAlterUser()
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenRole:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminAlterRole()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown ALTER target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminAlterUser() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenActive {
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminActivateUser()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenPassword {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
password, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd := NewCommand("admin_alter_user")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["password"] = password
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenSet {
|
|
|
|
|
return nil, fmt.Errorf("expected SET")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenRole {
|
|
|
|
|
return nil, fmt.Errorf("expected ROLE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
roleName, err := p.parseIdentifier()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("alter_user_role")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminActivateUser() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ACTIVE
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
// Accept 'on' or 'off' as identifier
|
|
|
|
|
status := p.curToken.Value
|
|
|
|
|
if status != "on" && status != "off" {
|
|
|
|
|
return nil, fmt.Errorf("expected 'on' or 'off', got %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_activate_user")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["activate_status"] = status
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminAlterRole() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ROLE
|
2026-06-22 17:33:47 +08:00
|
|
|
|
|
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type != TokenSet {
|
|
|
|
|
return nil, fmt.Errorf("expected SET")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type != TokenDescription {
|
|
|
|
|
return nil, fmt.Errorf("expected DESCRIPTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
description, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-22 17:33:47 +08:00
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_alter_role")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
cmd.Params["description"] = description
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-19 09:57:58 +08:00
|
|
|
// endregion ALTER commands
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminGrantCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume GRANT
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenAdmin {
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminGrantAdmin()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminGrantPermission()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminGrantAdmin() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ADMIN
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_grant_user_admin")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminGrantPermission() (*Command, error) {
|
2026-06-22 17:33:47 +08:00
|
|
|
actionListStr, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-22 17:33:47 +08:00
|
|
|
actions := strings.Split(actionListStr, ",")
|
|
|
|
|
p.nextToken()
|
|
|
|
|
for idx, _ := range actions {
|
|
|
|
|
actions[idx] = strings.TrimSpace(actions[idx])
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenOn {
|
|
|
|
|
return nil, fmt.Errorf("expected ON")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
resource, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type != TokenTo {
|
|
|
|
|
return nil, fmt.Errorf("expected TO")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type != TokenRole {
|
|
|
|
|
return nil, fmt.Errorf("expected ROLE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_grant_role_permission")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["actions"] = actions
|
|
|
|
|
cmd.Params["resource"] = resource
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminRevokeCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume REVOKE
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenAdmin {
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminRevokeAdmin()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminRevokePermission()
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminRevokeAdmin() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ADMIN
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_revoke_user_admin")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminRevokePermission() (*Command, error) {
|
2026-06-22 17:33:47 +08:00
|
|
|
actionListStr, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2026-06-22 17:33:47 +08:00
|
|
|
actions := strings.Split(actionListStr, ",")
|
|
|
|
|
p.nextToken()
|
|
|
|
|
for idx, _ := range actions {
|
|
|
|
|
actions[idx] = strings.TrimSpace(actions[idx])
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenOn {
|
|
|
|
|
return nil, fmt.Errorf("expected ON")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
resource, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenFrom {
|
|
|
|
|
return nil, fmt.Errorf("expected FROM")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenRole {
|
|
|
|
|
return nil, fmt.Errorf("expected ROLE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_revoke_role_permission")
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["actions"] = actions
|
|
|
|
|
cmd.Params["resource"] = resource
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminIdentifierList() ([]string, error) {
|
|
|
|
|
var list []string
|
|
|
|
|
|
|
|
|
|
ident, err := p.parseIdentifier()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
list = append(list, ident)
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
for p.curToken.Type == TokenComma {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
ident, err := p.parseIdentifier()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
list = append(list, ident)
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminSetCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume SET
|
|
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenLicense:
|
|
|
|
|
return p.parseAdminSetLicense()
|
|
|
|
|
case TokenVar:
|
|
|
|
|
return p.parseAdminSetVariable()
|
2026-06-22 19:03:36 +08:00
|
|
|
case TokenRole:
|
|
|
|
|
return p.parseAdminSetRoleDefaultModel()
|
2026-06-20 02:31:07 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown SET target: %s", p.curToken.Value)
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-06-20 02:31:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminSetLicense() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume LICENSE
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenConfig {
|
|
|
|
|
p.nextToken() // consume CONFIG
|
|
|
|
|
// SET LICENSE CONFIG <number1> <number2>
|
|
|
|
|
cmd := NewCommand("admin_set_license_config_command")
|
|
|
|
|
number1, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
number2, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd.Params["number1"] = number1
|
|
|
|
|
cmd.Params["number2"] = number2
|
|
|
|
|
return cmd, nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-06-20 02:31:07 +08:00
|
|
|
|
|
|
|
|
license, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-06-20 02:31:07 +08:00
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_set_license_command")
|
|
|
|
|
cmd.Params["license"] = license
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-20 02:31:07 +08:00
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminSetVariable() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume VAR
|
2026-06-22 17:33:47 +08:00
|
|
|
|
|
|
|
|
varName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-05-18 01:08:45 -10:00
|
|
|
varValue, err := p.parseVariableValue()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("set_variable")
|
|
|
|
|
cmd.Params["var_name"] = varName
|
|
|
|
|
cmd.Params["var_value"] = varValue
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
func (p *Parser) parseAdminSetRoleDefaultModel() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ROLE
|
|
|
|
|
|
|
|
|
|
roleName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenDefault {
|
|
|
|
|
return nil, fmt.Errorf("expected DEFAULT")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-04-20 15:31:12 +08:00
|
|
|
var modelType string
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
2026-04-20 15:31:12 +08:00
|
|
|
case TokenChat:
|
|
|
|
|
modelType = "chat"
|
|
|
|
|
case TokenVision:
|
|
|
|
|
modelType = "vision"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenEmbedding:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "embedding"
|
|
|
|
|
case TokenRerank:
|
|
|
|
|
modelType = "rerank"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenASR:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "asr"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenTTS:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "tts"
|
|
|
|
|
case TokenOCR:
|
|
|
|
|
modelType = "ocr"
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-06-22 19:03:36 +08:00
|
|
|
|
2026-06-15 10:10:14 +08:00
|
|
|
modelNameOrID, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
cmd := NewCommand("admin_set_role_default_model")
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
2026-03-25 21:39:14 +08:00
|
|
|
cmd.Params["model_type"] = modelType
|
2026-06-15 10:10:14 +08:00
|
|
|
if common.IsCompositeModelName(modelNameOrID) {
|
|
|
|
|
cmd.Params["composite_model_name"] = modelNameOrID
|
|
|
|
|
} else if common.IsUUID(modelNameOrID) {
|
|
|
|
|
cmd.Params["model_id"] = modelNameOrID
|
|
|
|
|
} else {
|
|
|
|
|
return nil, fmt.Errorf("invalid format of model name or ID: %s", modelNameOrID)
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
func (p *Parser) parseAdminResetCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume RESET
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenRole {
|
|
|
|
|
return nil, fmt.Errorf("expected ROLE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
roleName, err := p.parseQuotedString()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenDefault {
|
|
|
|
|
return nil, fmt.Errorf("expected DEFAULT")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
var modelType string
|
|
|
|
|
switch p.curToken.Type {
|
2026-04-20 15:31:12 +08:00
|
|
|
case TokenChat:
|
|
|
|
|
modelType = "chat"
|
|
|
|
|
case TokenVision:
|
|
|
|
|
modelType = "vision"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenEmbedding:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "embedding"
|
|
|
|
|
case TokenRerank:
|
|
|
|
|
modelType = "rerank"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenASR:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "asr"
|
2026-03-25 21:39:14 +08:00
|
|
|
case TokenTTS:
|
2026-04-20 15:31:12 +08:00
|
|
|
modelType = "tts"
|
|
|
|
|
case TokenOCR:
|
|
|
|
|
modelType = "ocr"
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 19:03:36 +08:00
|
|
|
cmd := NewCommand("admin_reset_role_default_model")
|
|
|
|
|
cmd.Params["role_name"] = roleName
|
|
|
|
|
cmd.Params["model_type"] = modelType
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminBenchmarkCommand() (*Command, error) {
|
|
|
|
|
cmd := NewCommand("benchmark")
|
|
|
|
|
|
|
|
|
|
p.nextToken() // consume BENCHMARK
|
|
|
|
|
concurrency, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["concurrency"] = concurrency
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
iterations, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["iterations"] = iterations
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
|
|
|
|
// Parse user_statement
|
|
|
|
|
nestedCmd, err := p.parseUserStatement() // Not only user statement
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["command"] = nestedCmd
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminUserStatement() (*Command, error) {
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenPing:
|
|
|
|
|
return p.parsePingServer()
|
|
|
|
|
case TokenShow:
|
|
|
|
|
return p.parseShowCommand()
|
|
|
|
|
case TokenCreate:
|
|
|
|
|
return p.parseCreateCommand()
|
|
|
|
|
case TokenDrop:
|
|
|
|
|
return p.parseDropCommand()
|
|
|
|
|
case TokenSet:
|
|
|
|
|
return p.parseSetCommand()
|
|
|
|
|
case TokenUnset:
|
|
|
|
|
return p.parseUnsetCommand()
|
|
|
|
|
case TokenReset:
|
|
|
|
|
return p.parseResetCommand()
|
|
|
|
|
case TokenList:
|
|
|
|
|
return p.parseListCommand()
|
|
|
|
|
case TokenParse:
|
|
|
|
|
return p.parseParseCommand()
|
|
|
|
|
case TokenImport:
|
|
|
|
|
return p.parseImportCommand()
|
2026-06-09 15:22:50 +08:00
|
|
|
case TokenRetrieve:
|
|
|
|
|
return p.parseRetrieveCommand()
|
2026-03-25 21:39:14 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("invalid user statement: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminStartService() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume START
|
|
|
|
|
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type != TokenService {
|
|
|
|
|
return nil, fmt.Errorf("expected SERVICE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
serviceIndex, err := p.parseNumber()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_start_service")
|
|
|
|
|
cmd.Params["service_index"] = serviceIndex
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminShutdownCommands() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume SHUTDOWN
|
2026-05-25 14:00:08 +08:00
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenService:
|
2026-06-22 17:33:47 +08:00
|
|
|
return p.parseAdminShutdownService()
|
2026-05-25 14:00:08 +08:00
|
|
|
case TokenIngestor:
|
2026-06-22 17:33:47 +08:00
|
|
|
return p.parseAdminShutdownIngestor()
|
2026-05-25 14:00:08 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected SERVICE or INGESTOR")
|
2026-03-25 21:39:14 +08:00
|
|
|
}
|
2026-05-25 14:00:08 +08:00
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminShutdownService() (*Command, error) {
|
2026-05-25 14:00:08 +08:00
|
|
|
p.nextToken() // consume SERVICE
|
2026-03-25 21:39:14 +08:00
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
serviceIndex, err := p.parseNumber()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_shutdown_service")
|
|
|
|
|
cmd.Params["service_index"] = serviceIndex
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminShutdownIngestor() (*Command, error) {
|
2026-05-25 14:00:08 +08:00
|
|
|
p.nextToken() // consume INGESTOR
|
|
|
|
|
|
|
|
|
|
ingestorName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_shutdown_ingestor_command")
|
|
|
|
|
cmd.Params["ingestor_name"] = ingestorName
|
|
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-05-25 14:00:08 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
func (p *Parser) parseAdminRestart() (*Command, error) {
|
2026-03-25 21:39:14 +08:00
|
|
|
p.nextToken() // consume RESTART
|
|
|
|
|
if p.curToken.Type != TokenService {
|
|
|
|
|
return nil, fmt.Errorf("expected SERVICE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
serviceIndex, err := p.parseNumber()
|
2026-03-25 21:39:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
cmd := NewCommand("admin_restart_service")
|
|
|
|
|
cmd.Params["service_index"] = serviceIndex
|
2026-03-25 21:39:14 +08:00
|
|
|
|
|
|
|
|
p.nextToken()
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 15:22:50 +08:00
|
|
|
func (p *Parser) parseAdminAddCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ADD
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenAPI:
|
|
|
|
|
return p.parseAddAPIServer()
|
|
|
|
|
case TokenAdmin:
|
|
|
|
|
return p.parseAddAdminServer()
|
2026-06-23 10:26:31 +08:00
|
|
|
case TokenProvider:
|
|
|
|
|
return p.parseAdminAddModelProvider()
|
2026-06-09 15:22:50 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown ADD target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 10:26:31 +08:00
|
|
|
// ADD PROVIDER <name>
|
|
|
|
|
// ADD PROVIDER <name> INSTANCE <name>
|
|
|
|
|
func (p *Parser) parseAdminAddModelProvider() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PROVIDER
|
|
|
|
|
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected provider name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenInstance {
|
|
|
|
|
return p.parseAdminAddModelInstance(providerName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_add_provider")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminAddModelInstance(providerName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume INSTANCE
|
|
|
|
|
|
|
|
|
|
instanceName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected model instance name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenModel {
|
|
|
|
|
return p.parseAdminAddModel(providerName, instanceName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_add_model_instance")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["instance_name"] = instanceName
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminAddModel(providerName, instanceName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MODEL
|
|
|
|
|
|
|
|
|
|
modelName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected model name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_add_models")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["instance_name"] = instanceName
|
|
|
|
|
cmd.Params["model_names"] = []string{modelName}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminDeleteCommands() (*Command, error) {
|
2026-06-09 15:22:50 +08:00
|
|
|
p.nextToken() // consume DELETE
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenAPI:
|
|
|
|
|
return p.parseDeleteAPIServer()
|
|
|
|
|
case TokenAdmin:
|
|
|
|
|
return p.parseDeleteAdminServer()
|
2026-06-23 10:26:31 +08:00
|
|
|
case TokenProvider:
|
|
|
|
|
return p.parseAdminDeleteProvider()
|
2026-06-09 15:22:50 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown ADD target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 10:26:31 +08:00
|
|
|
// DELETE PROVIDER <name> command
|
|
|
|
|
// DELETE PROVIDER <name> INSTANCE <name> command
|
|
|
|
|
// DELETE PROVIDER <name> INSTANCE <name> MODEL <name>
|
|
|
|
|
func (p *Parser) parseAdminDeleteProvider() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PROVIDER
|
|
|
|
|
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected provider name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenInstance {
|
|
|
|
|
return p.parseAdminDeleteModelInstance(providerName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_delete_model_providers")
|
|
|
|
|
cmd.Params["provider_names"] = []string{providerName}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DELETE PROVIDER <name> INSTANCE <name> command
|
|
|
|
|
// DELETE PROVIDER <name> INSTANCE <name> MODEL <name>
|
|
|
|
|
func (p *Parser) parseAdminDeleteModelInstance(providerName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume INSTANCE
|
|
|
|
|
|
|
|
|
|
instanceName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected model instance name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenModel {
|
|
|
|
|
return p.parseAdminDeleteModel(providerName, instanceName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_delete_model_instance")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["instance_names"] = []string{instanceName}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DELETE PROVIDER <name> INSTANCE <name> MODEL <name>
|
|
|
|
|
func (p *Parser) parseAdminDeleteModel(providerName, instanceName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MODEL
|
|
|
|
|
|
|
|
|
|
modelName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected model name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_delete_model")
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["instance_name"] = instanceName
|
|
|
|
|
cmd.Params["model_names"] = []string{modelName}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 15:22:50 +08:00
|
|
|
func (p *Parser) parseAdminSaveCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume SAVE
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenConfig:
|
|
|
|
|
return p.parseSaveConfig()
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("unknown ADD target: %s", p.curToken.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 10:57:00 +08:00
|
|
|
func (p *Parser) parseAdminUseCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USE
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenAPI:
|
|
|
|
|
return p.parseUseAPIServer()
|
|
|
|
|
case TokenAdmin:
|
|
|
|
|
return p.parseUseAdminServer()
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected MODEL or SKILL after USE")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 14:00:08 +08:00
|
|
|
func (p *Parser) parseStartIngestion() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume Start
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenIngestion {
|
|
|
|
|
return nil, fmt.Errorf("expect INGESTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume Ingest
|
|
|
|
|
|
|
|
|
|
uri, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_start_ingestion_command")
|
|
|
|
|
cmd.Params["uri"] = uri
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-05-25 14:00:08 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseStopIngestion() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume Stop
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenIngestion {
|
|
|
|
|
return nil, fmt.Errorf("expect INGESTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume Ingest
|
|
|
|
|
|
|
|
|
|
taskID, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_stop_ingestion_command")
|
|
|
|
|
cmd.Params["task_id"] = taskID
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-05-25 14:00:08 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Parser) parseAdminIngestCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume Ingest
|
|
|
|
|
|
|
|
|
|
uri, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_ingest_command")
|
|
|
|
|
cmd.Params["uri"] = uri
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-05-25 14:00:08 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
2026-03-25 21:39:14 +08:00
|
|
|
func (p *Parser) parseAdminUnsetCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume UNSET
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenToken {
|
|
|
|
|
return nil, fmt.Errorf("expected TOKEN after UNSET")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// Semicolon is optional
|
2026-03-25 21:39:14 +08:00
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return NewCommand("unset_token"), nil
|
|
|
|
|
}
|
2026-06-12 14:56:44 +08:00
|
|
|
|
|
|
|
|
func (p *Parser) parseMessageQueueCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume MESSAGE_QUEUE
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenShow:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("user_show_message_queue_command")
|
|
|
|
|
|
|
|
|
|
case TokenList:
|
|
|
|
|
p.nextToken() // consume LIST
|
|
|
|
|
|
|
|
|
|
cmd = NewCommand("user_list_message_queue_command")
|
|
|
|
|
if p.curToken.Type == TokenPending {
|
|
|
|
|
cmd.Params["pending"] = true
|
|
|
|
|
p.nextToken() // consume PENDING
|
|
|
|
|
} else {
|
|
|
|
|
cmd.Params["pending"] = false
|
|
|
|
|
}
|
|
|
|
|
case TokenPublish:
|
|
|
|
|
p.nextToken() // consume PUBLISH
|
|
|
|
|
|
|
|
|
|
message, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("expected message after PUBLISH")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken() // consume message
|
|
|
|
|
|
|
|
|
|
cmd = NewCommand("user_publish_message_command")
|
|
|
|
|
cmd.Params["message"] = message
|
|
|
|
|
case TokenPull:
|
|
|
|
|
p.nextToken() // consume PULL
|
|
|
|
|
|
|
|
|
|
messageCount, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
messageCount = 1
|
|
|
|
|
} else {
|
|
|
|
|
p.nextToken() // consume NUMBER
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if messageCount <= 0 || messageCount > 100 {
|
|
|
|
|
return nil, fmt.Errorf("message count cannot be less than 0 or greater than 100")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd = NewCommand("user_pull_message_command")
|
|
|
|
|
cmd.Params["message_count"] = messageCount
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenNoACK {
|
|
|
|
|
cmd.Params["ack_policy"] = "NOACK"
|
|
|
|
|
p.nextToken() // consume NOACK
|
|
|
|
|
} else {
|
|
|
|
|
cmd.Params["ack_policy"] = "ACK"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected WITH")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 17:33:47 +08:00
|
|
|
// REMOVE INGESTION TASK 'task_id';
|
|
|
|
|
// REMOVE USER 'user@example.com' INGESTION TASKS 'created';
|
|
|
|
|
func (p *Parser) parseAdminRemoveCommands() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume REMOVE
|
2026-06-12 14:56:44 +08:00
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenIngestion:
|
|
|
|
|
return p.parseAdminRemoveIngestionTasks()
|
2026-06-18 17:50:21 +08:00
|
|
|
case TokenUser:
|
|
|
|
|
return p.parseAdminRemoveUserCommand()
|
2026-06-12 14:56:44 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected SERVICE")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-18 15:21:44 +08:00
|
|
|
|
|
|
|
|
// SHOW USERS SUMMARY;
|
|
|
|
|
// SHOW USERS ACTIVITY;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminShowUsersCommands() (*Command, error) {
|
2026-06-18 15:21:44 +08:00
|
|
|
p.nextToken() // consume USERS
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenSummary:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd := NewCommand("admin_show_users_summary_command")
|
|
|
|
|
return cmd, nil
|
|
|
|
|
case TokenActivity:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminShowUsersActivity()
|
2026-06-18 15:21:44 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("invalid command")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW USERS ACTIVITY WINDOW 2 DAYS 30;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminShowUsersActivity() (*Command, error) {
|
2026-06-18 15:21:44 +08:00
|
|
|
p.nextToken() // consume ACTIVITY
|
|
|
|
|
|
|
|
|
|
var days int
|
|
|
|
|
var err error
|
|
|
|
|
var windowSize int
|
|
|
|
|
|
|
|
|
|
commandLoop:
|
|
|
|
|
for {
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenDays:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
days, err = p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if days < 1 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of DAYS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenWindow:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
windowSize, err = p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if windowSize < 0 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of WINDOWS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenSemicolon:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
break commandLoop // done
|
|
|
|
|
default:
|
|
|
|
|
// No more options to process
|
|
|
|
|
break commandLoop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_show_users_activity_command")
|
|
|
|
|
cmd.Params["days"] = days
|
|
|
|
|
cmd.Params["window"] = windowSize
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LIST USERS;
|
|
|
|
|
// LIST USERS ACTIVE 30 DAYS; // default 7 days
|
|
|
|
|
// LIST USERS INACTIVE 30 DAYS; // default 7 days
|
|
|
|
|
// LIST USERS STORAGE TOP 10;
|
|
|
|
|
// LIST USERS DOCUMENTS TOP 10;
|
|
|
|
|
// LIST USERS INDEX TOP 10;
|
|
|
|
|
// LIST USERS QUOTA TOP 10;
|
|
|
|
|
// LIST USERS QUOTA OVER;
|
|
|
|
|
// LIST USERS PLAN 'plan_name' QUOTA OVER DAYS 30; // default 7 days
|
|
|
|
|
// LIST USERS PLAN 'plan_name' DAYS 30; // default 7 days
|
|
|
|
|
func (p *Parser) parseAdminListUsersCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USERS
|
|
|
|
|
|
|
|
|
|
var orderBy string
|
|
|
|
|
var userStatus string
|
|
|
|
|
var top *int
|
|
|
|
|
var plan *string
|
|
|
|
|
var quota *int
|
|
|
|
|
var days *int
|
|
|
|
|
condition := false
|
|
|
|
|
commandLoop:
|
|
|
|
|
for {
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenTop:
|
|
|
|
|
condition = true
|
|
|
|
|
p.nextToken()
|
|
|
|
|
topInt, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if topInt < 0 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of TOP")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
top = &topInt
|
|
|
|
|
case TokenDays:
|
|
|
|
|
condition = true
|
|
|
|
|
p.nextToken()
|
|
|
|
|
daysInt, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if daysInt < 0 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of DAYS")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
days = &daysInt
|
|
|
|
|
case TokenPlan:
|
|
|
|
|
condition = true
|
|
|
|
|
p.nextToken()
|
|
|
|
|
planStr, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if planStr == "" {
|
|
|
|
|
return nil, fmt.Errorf("invalid plan")
|
|
|
|
|
}
|
|
|
|
|
plan = &planStr
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenQuota:
|
|
|
|
|
condition = true
|
|
|
|
|
p.nextToken()
|
|
|
|
|
quotaInt, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if quotaInt < 0 {
|
|
|
|
|
return nil, fmt.Errorf("invalid number of QUOTA")
|
|
|
|
|
}
|
|
|
|
|
quota = "aInt
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenDocuments, TokenIndex, TokenStorage:
|
|
|
|
|
condition = true
|
|
|
|
|
if orderBy != "" {
|
|
|
|
|
return nil, fmt.Errorf("order by already set")
|
|
|
|
|
}
|
|
|
|
|
orderBy = p.curToken.Value
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenActive, TokenInactive:
|
|
|
|
|
condition = true
|
|
|
|
|
userStatus = p.curToken.Value
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenSemicolon:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
break commandLoop // done
|
|
|
|
|
default:
|
|
|
|
|
// No more options to process
|
|
|
|
|
break commandLoop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !condition {
|
|
|
|
|
return NewCommand("admin_list_users_command"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_list_users_condition_command")
|
|
|
|
|
if orderBy != "" {
|
|
|
|
|
cmd.Params["order_by"] = orderBy
|
|
|
|
|
}
|
|
|
|
|
if userStatus != "" {
|
|
|
|
|
cmd.Params["user_status"] = userStatus
|
|
|
|
|
}
|
|
|
|
|
if top != nil {
|
|
|
|
|
cmd.Params["top"] = *top
|
|
|
|
|
}
|
|
|
|
|
if plan != nil {
|
|
|
|
|
cmd.Params["plan"] = *plan
|
|
|
|
|
}
|
|
|
|
|
if quota != nil {
|
|
|
|
|
cmd.Params["quota"] = *quota
|
|
|
|
|
}
|
|
|
|
|
if days != nil {
|
|
|
|
|
cmd.Params["days"] = *days
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW DATA SUMMARY;
|
|
|
|
|
// SHOW DATA ORPHAN;
|
|
|
|
|
// SHOW DATA STORAGE;
|
|
|
|
|
// SHOW DATA INDEX;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminShowData() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume DATA
|
2026-06-18 15:21:44 +08:00
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenSummary:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_data_summary")
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenOrphan:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_data_orphan")
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenStorage:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_data_storage")
|
2026-06-18 15:21:44 +08:00
|
|
|
case TokenIndex:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_data_index")
|
2026-06-18 15:21:44 +08:00
|
|
|
default:
|
2026-06-22 08:19:23 +08:00
|
|
|
return nil, fmt.Errorf("expected SUMMARY, ORPHAN, STORAGE, INDEX after DATA")
|
2026-06-18 15:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SHOW QUOTA SUMMARY;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminShowQuota() (*Command, error) {
|
2026-06-18 15:21:44 +08:00
|
|
|
p.nextToken() // consume QUOTA
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenSummary:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_quota_summary")
|
2026-06-18 15:21:44 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected SUMMARY after QUOTA")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 17:09:20 +08:00
|
|
|
// SHOW TASKS SUMMARY;
|
2026-06-22 08:19:23 +08:00
|
|
|
func (p *Parser) parseAdminShowTasks() (*Command, error) {
|
2026-06-18 17:09:20 +08:00
|
|
|
p.nextToken() // consume TASKS
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenSummary:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_show_tasks_summary")
|
2026-06-18 17:09:20 +08:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected SUMMARY after TASKS")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 15:21:44 +08:00
|
|
|
// PURGE PREVIEW ORPHAN
|
|
|
|
|
// PURGE ORPHAN
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW USER 'user@example.com';
|
|
|
|
|
// PURGE USER
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW USERS PLAN 'plan_name' DAYS 30; // default 7 days
|
|
|
|
|
// PURGE USERS PLAN 'plan_name' DAYS 30;
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW USERS INACTIVE PLAN 'plan_name' DAYS 30;
|
|
|
|
|
// PURGE USERS INACTIVE PLAN 'plan_name' DAYS 30;
|
|
|
|
|
func (p *Parser) parseAdminPurgeCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PURGE
|
|
|
|
|
var preview = false
|
|
|
|
|
if p.curToken.Type == TokenPreview {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
preview = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenOrphan:
|
|
|
|
|
return p.parseAdminPurgeOrphanCommand(preview)
|
|
|
|
|
case TokenUser:
|
|
|
|
|
return p.parseAdminPurgeUserCommand(preview)
|
|
|
|
|
case TokenUsers:
|
|
|
|
|
return p.parseAdminPurgeUsersCommand(preview)
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected PREVIEW, USER, USERS after PURGE")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW ORPHAN
|
|
|
|
|
// PURGE ORPHAN
|
|
|
|
|
func (p *Parser) parseAdminPurgeOrphanCommand(preview bool) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume ORPHAN
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_purge_orphan_command")
|
|
|
|
|
cmd.Params["preview"] = preview
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW USER 'user@example.com';
|
|
|
|
|
// PURGE USER 'user@example.com';
|
|
|
|
|
func (p *Parser) parseAdminPurgeUserCommand(preview bool) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd := NewCommand("admin_purge_user_command")
|
|
|
|
|
cmd.Params["preview"] = preview
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PURGE PREVIEW USERS PLAN 'plan_name' DAYS 30; // default 7 days
|
|
|
|
|
// PURGE USERS PLAN 'plan_name' DAYS 30;
|
|
|
|
|
// PURGE PREVIEW USERS INACTIVE PLAN 'plan_name' DAYS 30;
|
|
|
|
|
// PURGE USERS INACTIVE PLAN 'plan_name' DAYS 30;
|
|
|
|
|
func (p *Parser) parseAdminPurgeUsersCommand(preview bool) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USERS
|
|
|
|
|
|
|
|
|
|
var userStatus *string = nil
|
|
|
|
|
var days *int = nil
|
|
|
|
|
var planName *string = nil
|
|
|
|
|
|
|
|
|
|
commandLoop:
|
|
|
|
|
for {
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenPlan:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if planName != nil {
|
|
|
|
|
return nil, fmt.Errorf("duplicate PLAN after USERS")
|
|
|
|
|
}
|
|
|
|
|
plan, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
planName = &plan
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenDays:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if days != nil {
|
|
|
|
|
return nil, fmt.Errorf("duplicate DAYS after USERS")
|
|
|
|
|
}
|
|
|
|
|
dayCount, err := p.parseNumber()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
days = &dayCount
|
|
|
|
|
p.nextToken()
|
|
|
|
|
case TokenInactive:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if userStatus != nil {
|
|
|
|
|
return nil, fmt.Errorf("duplicate INACTIVE or ACTIVE after USERS")
|
|
|
|
|
}
|
|
|
|
|
inactiveStatus := "inactive"
|
|
|
|
|
userStatus = &inactiveStatus
|
|
|
|
|
case TokenActive:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if userStatus != nil {
|
|
|
|
|
return nil, fmt.Errorf("duplicate INACTIVE or ACTIVE after USERS")
|
|
|
|
|
}
|
|
|
|
|
activeStatus := "active"
|
|
|
|
|
userStatus = &activeStatus
|
|
|
|
|
case TokenSemicolon:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
break commandLoop // done
|
|
|
|
|
default:
|
|
|
|
|
// No more options to process
|
|
|
|
|
break commandLoop
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_purge_users_command")
|
|
|
|
|
cmd.Params["preview"] = preview
|
|
|
|
|
if planName != nil {
|
|
|
|
|
cmd.Params["plan_name"] = *planName
|
|
|
|
|
}
|
|
|
|
|
if userStatus != nil {
|
|
|
|
|
cmd.Params["user_status"] = *userStatus
|
|
|
|
|
}
|
|
|
|
|
if days != nil {
|
|
|
|
|
cmd.Params["days"] = *days
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
2026-06-18 17:50:21 +08:00
|
|
|
|
|
|
|
|
// LIST USER 'user@example.com' INGESTION TASKS;
|
2026-06-22 08:19:23 +08:00
|
|
|
// LIST USER 'user@example.com' DATASETS;
|
|
|
|
|
// LIST USER 'user@example.com' AGENTS;
|
|
|
|
|
// LIST USER 'user@example.com' CHATS;
|
|
|
|
|
// LIST USER 'user@example.com' SEARCHES;
|
|
|
|
|
// LIST USER 'user@example.com' MODELS; // all added models
|
|
|
|
|
// LIST USER 'user@example.com' FILES;
|
|
|
|
|
// LIST USER 'user@example.com' KEYS;
|
2026-06-21 16:50:02 +08:00
|
|
|
// LIST USER 'user_name' PROVIDER 'provider_name' INSTANCE 'instance_name' MODELS;
|
2026-06-18 17:50:21 +08:00
|
|
|
func (p *Parser) parseAdminListUserCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenIngestion:
|
2026-06-22 08:19:23 +08:00
|
|
|
return p.parseAdminListUserIngestionTasks(userName)
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenDatasets:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_datasets")
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenAgents:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_agents")
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenChats:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_chats")
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenSearches:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_searches")
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenModels:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_models")
|
2026-06-19 15:09:54 +08:00
|
|
|
case TokenFiles:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_files")
|
2026-06-20 02:31:07 +08:00
|
|
|
case TokenKeys:
|
|
|
|
|
p.nextToken()
|
2026-06-22 08:19:23 +08:00
|
|
|
cmd = NewCommand("admin_list_user_keys")
|
|
|
|
|
case TokenProvider:
|
|
|
|
|
return p.parseAdminListUserProviderInstanceModels(userName)
|
|
|
|
|
case TokenProviders:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("admin_list_user_providers")
|
|
|
|
|
case TokenDefault:
|
|
|
|
|
return p.parseAdminListUserDefaultModels(userName)
|
2026-06-18 17:50:21 +08:00
|
|
|
default:
|
2026-06-22 08:19:23 +08:00
|
|
|
return nil, fmt.Errorf("expected INGESTION or DATASETS or AGENTS or CHATS or SEARCHES or MODELS or FILES or KEYS after USER")
|
2026-06-19 15:09:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Semicolon is optional
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
2026-06-18 17:50:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-22 08:19:23 +08:00
|
|
|
// LIST USER 'user@example.com' INGESTION TASKS 'status';
|
|
|
|
|
func (p *Parser) parseAdminListUserIngestionTasks(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume INGESTION
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS after INGESTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_list_user_ingestion_tasks")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenQuotedString {
|
|
|
|
|
var status string
|
|
|
|
|
var err error
|
|
|
|
|
status, err = p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["status"] = status
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LIST USER 'user_name' PROVIDER 'provider_name' INSTANCES;
|
|
|
|
|
// LIST USER 'user_name' PROVIDER 'provider_name' INSTANCE 'instance_name' MODELS;
|
|
|
|
|
func (p *Parser) parseAdminListUserProviderInstanceModels(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume PROVIDER
|
|
|
|
|
|
|
|
|
|
providerName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenInstances {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd := NewCommand("admin_list_user_provider_instances")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenInstance {
|
|
|
|
|
return nil, fmt.Errorf("expected INSTANCE after PROVIDER")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
instanceName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenModels {
|
|
|
|
|
return nil, fmt.Errorf("expected MODELS after INSTANCE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_list_user_provider_instance_models")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
cmd.Params["provider_name"] = providerName
|
|
|
|
|
cmd.Params["instance_name"] = instanceName
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LIST USER 'user_name' DEFAULT MODELS;
|
|
|
|
|
func (p *Parser) parseAdminListUserDefaultModels(userName string) (*Command, error) {
|
|
|
|
|
p.nextToken() // consume DEFAULT
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type != TokenModels {
|
|
|
|
|
return nil, fmt.Errorf("expected MODELS after INSTANCE")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
cmd := NewCommand("admin_list_user_default_models")
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
|
|
|
|
|
if p.curToken.Type == TokenSemicolon {
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 17:50:21 +08:00
|
|
|
// STOP USER 'user@example.com' INGESTION TASKS 'created';
|
|
|
|
|
func (p *Parser) parseAdminStopUserCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenIngestion:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS after INGESTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("admin_stop_user_ingestion_tasks_command")
|
|
|
|
|
if p.curToken.Type == TokenQuotedString {
|
|
|
|
|
var status string
|
|
|
|
|
status, err = p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["status"] = status
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected INGESTION after USER")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// REMOVE USER 'user@example.com' INGESTION TASKS 'created';
|
|
|
|
|
func (p *Parser) parseAdminRemoveUserCommand() (*Command, error) {
|
|
|
|
|
p.nextToken() // consume USER
|
|
|
|
|
|
|
|
|
|
userName, err := p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
|
|
|
|
|
var cmd *Command
|
|
|
|
|
switch p.curToken.Type {
|
|
|
|
|
case TokenIngestion:
|
|
|
|
|
p.nextToken()
|
|
|
|
|
if p.curToken.Type != TokenTasks {
|
|
|
|
|
return nil, fmt.Errorf("expected TASKS after INGESTION")
|
|
|
|
|
}
|
|
|
|
|
p.nextToken()
|
|
|
|
|
cmd = NewCommand("admin_remove_user_ingestion_tasks_command")
|
|
|
|
|
if p.curToken.Type == TokenQuotedString {
|
|
|
|
|
var status string
|
|
|
|
|
status, err = p.parseQuotedString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cmd.Params["status"] = status
|
|
|
|
|
p.nextToken()
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("expected INGESTION after USER")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd.Params["user_name"] = userName
|
|
|
|
|
return cmd, nil
|
|
|
|
|
}
|