// // 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. // package cli import ( "fmt" "ragflow/internal/common" "strings" ) // Command parsers func (p *Parser) parseAdminLoginUser() (*Command, error) { cmd := NewCommand("login_user") p.nextToken() // consume LOGIN if p.curToken.Type != TokenAdmin { return nil, fmt.Errorf("expected ADMIN after LOGIN") } p.nextToken() email, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["email"] = email p.nextToken() // Optional: PASSWORD 'password' if p.curToken.Type == TokenPassword { p.nextToken() password, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["password"] = password p.nextToken() } // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminLogout() (*Command, error) { cmd := NewCommand("logout") p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminPingServer() (*Command, error) { cmd := NewCommand("ping") p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRegisterCommand() (*Command, error) { cmd := NewCommand("register_user") if err := p.expectPeek(TokenUser); err != nil { return nil, err } p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["user_name"] = userName p.nextToken() if p.curToken.Type != TokenAs { return nil, fmt.Errorf("expected AS") } p.nextToken() nickname, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["nickname"] = nickname p.nextToken() if p.curToken.Type != TokenPassword { return nil, fmt.Errorf("expected PASSWORD") } p.nextToken() password, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["password"] = password p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListCommand() (*Command, error) { p.nextToken() // consume LIST switch p.curToken.Type { case TokenServices: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_services"), nil case TokenUsers: return p.parseAdminListUsersCommand() case TokenUser: return p.parseAdminListUserCommand() case TokenRoles: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_roles"), nil case TokenVars: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_variables"), nil case TokenConfigs: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_configs"), nil case TokenEnvs: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_environments"), nil case TokenDatasets: return p.parseAdminListDatasets() case TokenAgents: return p.parseAdminListAgents() case TokenTokens: return p.parseAdminListTokens() case TokenModel: return p.parseAdminListModelProviders() case TokenDefault: return p.parseAdminListDefaultModels() case TokenAvailable: return p.parseCommonListProviders() case TokenModels: return p.parseListModelsOfProvider() case TokenChats: p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_user_chats"), nil case TokenFiles: return p.parseAdminListFiles() case TokenIngestors: return p.parseAdminListIngestors() case TokenIngestion: return p.parseAdminListIngestionTasks() case TokenAPI: return p.parseListApiCommand() default: return nil, fmt.Errorf("unknown LIST target: %s", p.curToken.Value) } } func (p *Parser) parseAdminListDatasets() (*Command, error) { cmd := NewCommand("list_user_datasets") p.nextToken() // consume DATASETS if p.curToken.Type == TokenSemicolon { return cmd, nil } if p.curToken.Type == TokenOf { p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd = NewCommand("list_datasets") cmd.Params["user_name"] = userName p.nextToken() } // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListAgents() (*Command, error) { p.nextToken() // consume AGENTS if p.curToken.Type == TokenSemicolon { return NewCommand("list_user_agents"), nil } if p.curToken.Type != TokenOf { return nil, fmt.Errorf("expected OF") } p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("list_agents") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListTokens() (*Command, error) { p.nextToken() // consume TOKENS cmd := NewCommand("list_tokens") // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListModelProviders() (*Command, error) { p.nextToken() // consume MODEL if p.curToken.Type != TokenProviders { return nil, fmt.Errorf("expected PROVIDERS") } p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_user_model_providers"), nil } func (p *Parser) parseAdminListDefaultModels() (*Command, error) { p.nextToken() // consume DEFAULT if p.curToken.Type != TokenModels { return nil, fmt.Errorf("expected MODELS") } p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("list_user_default_models"), nil } func (p *Parser) parseCommonListProviders() (*Command, error) { p.nextToken() // consume AVAILABLE if p.curToken.Type != TokenProviders { return nil, fmt.Errorf("expected PROVIDERS") } return NewCommand("list_available_providers"), nil } 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() // Semicolon is optional for UNSET TOKEN 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 // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } else { return nil, fmt.Errorf("expected PROVIDERS or MODELS") } } 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() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListIngestors() (*Command, error) { p.nextToken() // consume TASKS cmd := NewCommand("admin_list_ingestors") return cmd, nil } 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") } // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRemoveIngestionTasks() (*Command, error) { p.nextToken() // consume Ingestion 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 // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminListIngestionTasks() (*Command, error) { p.nextToken() // consume Ingestion if p.curToken.Type != TokenTasks { return nil, fmt.Errorf("expected TASKS") } p.nextToken() // consume TASKS cmd := NewCommand("list_admin_ingestion_tasks") // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShowCommand() (*Command, error) { p.nextToken() // consume SHOW switch p.curToken.Type { case TokenVersion: return p.parseAdminShowVersionCommand() case TokenCurrent: return p.parseAdminShowCurrentCommand() case TokenRole: return p.parseAdminShowRoleCommand() case TokenVar: return p.parseShowVariable() case TokenService: return p.parseShowService() case TokenProvider: return p.parseShowProvider() case TokenModel: return p.parseShowModel() case TokenAdmin: return p.parseUserShowAdmin() case TokenAPI: return p.parseUserShowAPI() case TokenUser: return p.parseAdminShowUserCommand() case TokenUsers: return p.parseAdminShowUsersCommand() case TokenData: return p.parseAdminShowDataCommand() case TokenQuota: return p.parseAdminShowQuotaCommand() case TokenTasks: return p.parseAdminShowQuotaCommand() default: return nil, fmt.Errorf("unknown SHOW target: %s", p.curToken.Value) } } func (p *Parser) parseAdminShowUser() (*Command, error) { p.nextToken() // consume USER // Check for PERMISSION if p.curToken.Type == TokenPermission { p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("show_user_permission") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for SHOW TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("show_user") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShowRoleCommand() (*Command, error) { p.nextToken() // consume ROLE roleName, err := p.parseIdentifier() if err != nil { return nil, err } cmd := NewCommand("show_role") cmd.Params["role_name"] = roleName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShowVariable() (*Command, error) { p.nextToken() // consume VAR varName, err := p.parseIdentifier() if err != nil { return nil, err } cmd := NewCommand("show_variable") cmd.Params["var_name"] = varName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShowService() (*Command, error) { p.nextToken() // consume SERVICE serviceNum, err := p.parseNumber() if err != nil { return nil, err } cmd := NewCommand("show_service") cmd.Params["number"] = serviceNum p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminCreateCommand() (*Command, error) { p.nextToken() // consume CREATE switch p.curToken.Type { case TokenUser: return p.parseCreateUser() case TokenRole: return p.parseCreateRole() case TokenModel: return p.parseCreateModelProvider() case TokenDataset: return p.parseCreateDataset() case TokenChat: return p.parseCreateChat() case TokenToken: return p.parseCreateToken() default: return nil, fmt.Errorf("unknown CREATE target: %s", p.curToken.Value) } } func (p *Parser) parseAdminCreateToken() (*Command, error) { p.nextToken() // consume TOKEN // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("create_token"), nil } func (p *Parser) parseAdminCreateUser() (*Command, error) { p.nextToken() // consume USER userName, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() password, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("create_user") cmd.Params["user_name"] = userName cmd.Params["password"] = password cmd.Params["role"] = "user" p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminCreateRole() (*Command, error) { p.nextToken() // consume ROLE roleName, err := p.parseIdentifier() if err != nil { return nil, err } cmd := NewCommand("create_role") cmd.Params["role_name"] = roleName p.nextToken() if p.curToken.Type == TokenDescription { p.nextToken() description, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["description"] = description p.nextToken() } // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminCreateModelProvider() (*Command, error) { p.nextToken() // consume MODEL if p.curToken.Type != TokenProvider { return nil, fmt.Errorf("expected PROVIDER") } p.nextToken() providerName, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() providerKey, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("create_model_provider") cmd.Params["provider_name"] = providerName cmd.Params["provider_key"] = providerKey p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminCreateDataset() (*Command, error) { p.nextToken() // consume DATASET datasetName, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() if p.curToken.Type != TokenWith { return nil, fmt.Errorf("expected WITH") } p.nextToken() if p.curToken.Type != TokenEmbedding { return nil, fmt.Errorf("expected EMBEDDING") } p.nextToken() embedding, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() cmd := NewCommand("create_user_dataset") cmd.Params["dataset_name"] = datasetName cmd.Params["embedding"] = embedding if p.curToken.Type == TokenParser { p.nextToken() parserType, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["parser_type"] = parserType p.nextToken() } else if p.curToken.Type == TokenPipeline { p.nextToken() pipeline, err := p.parseQuotedString() if err != nil { return nil, err } cmd.Params["pipeline"] = pipeline p.nextToken() } else { return nil, fmt.Errorf("expected PARSER or PIPELINE") } // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminCreateChat() (*Command, error) { p.nextToken() // consume CHAT chatName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("create_user_chat") cmd.Params["chat_name"] = chatName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminDropCommand() (*Command, error) { p.nextToken() // consume DROP switch p.curToken.Type { case TokenUser: return p.parseDropUser() case TokenRole: return p.parseDropRole() case TokenDataset: return p.parseDropDataset() case TokenChat: return p.parseDropChat() case TokenToken: return p.parseDropToken() default: return nil, fmt.Errorf("unknown DROP target: %s", p.curToken.Value) } } func (p *Parser) parseAdminDropToken() (*Command, error) { p.nextToken() // consume TOKEN tokenValue, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() if p.curToken.Type != TokenOf { return nil, fmt.Errorf("expected OF") } p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("drop_token") cmd.Params["token"] = tokenValue cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminDropUser() (*Command, error) { p.nextToken() // consume USER userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("drop_user") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminDropRole() (*Command, error) { p.nextToken() // consume ROLE roleName, err := p.parseIdentifier() if err != nil { return nil, err } cmd := NewCommand("drop_role") cmd.Params["role_name"] = roleName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminDropModelProvider() (*Command, error) { p.nextToken() // consume MODEL if p.curToken.Type != TokenProvider { return nil, fmt.Errorf("expected PROVIDER") } p.nextToken() providerName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("drop_model_provider") cmd.Params["provider_name"] = providerName p.nextToken() // Semicolon is optional for UNSET TOKEN 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() // Semicolon is optional for UNSET TOKEN 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() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminAlterCommand() (*Command, error) { p.nextToken() // consume ALTER switch p.curToken.Type { case TokenUser: return p.parseAlterUser() case TokenRole: return p.parseAlterRole() 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 { return p.parseActivateUser() } 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 } cmd := NewCommand("alter_user") cmd.Params["user_name"] = userName cmd.Params["password"] = password p.nextToken() // Semicolon is optional for SHOW TOKEN 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() // Semicolon is optional for UNSET TOKEN 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) } cmd := NewCommand("activate_user") cmd.Params["user_name"] = userName cmd.Params["activate_status"] = status p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminAlterRole() (*Command, error) { p.nextToken() // consume ROLE roleName, err := p.parseIdentifier() 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 != TokenDescription { return nil, fmt.Errorf("expected DESCRIPTION") } p.nextToken() description, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("alter_role") cmd.Params["role_name"] = roleName cmd.Params["description"] = description p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminGrantCommand() (*Command, error) { p.nextToken() // consume GRANT if p.curToken.Type == TokenAdmin { return p.parseGrantAdmin() } return p.parseGrantPermission() } func (p *Parser) parseAdminGrantAdmin() (*Command, error) { p.nextToken() // consume ADMIN userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("grant_admin") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminGrantPermission() (*Command, error) { actions, err := p.parseIdentifierList() if err != nil { return nil, err } if p.curToken.Type != TokenOn { return nil, fmt.Errorf("expected ON") } p.nextToken() resource, err := p.parseIdentifier() if err != nil { return nil, err } p.nextToken() if p.curToken.Type != TokenTo { return nil, fmt.Errorf("expected TO") } 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("grant_permission") cmd.Params["actions"] = actions cmd.Params["resource"] = resource cmd.Params["role_name"] = roleName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRevokeCommand() (*Command, error) { p.nextToken() // consume REVOKE if p.curToken.Type == TokenAdmin { return p.parseRevokeAdmin() } return p.parseRevokePermission() } func (p *Parser) parseAdminRevokeAdmin() (*Command, error) { p.nextToken() // consume ADMIN userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("revoke_admin") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRevokePermission() (*Command, error) { actions, err := p.parseIdentifierList() if err != nil { return nil, err } if p.curToken.Type != TokenOn { return nil, fmt.Errorf("expected ON") } p.nextToken() resource, err := p.parseIdentifier() 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() roleName, err := p.parseIdentifier() if err != nil { return nil, err } cmd := NewCommand("revoke_permission") cmd.Params["actions"] = actions cmd.Params["resource"] = resource cmd.Params["role_name"] = roleName p.nextToken() // Semicolon is optional for UNSET TOKEN 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 if p.curToken.Type == TokenVar { return p.parseSetVariable() } if p.curToken.Type == TokenDefault { return p.parseSetDefault() } if p.curToken.Type == TokenToken { return p.parseSetToken() } return nil, fmt.Errorf("unknown SET target: %s", p.curToken.Value) } func (p *Parser) parseAdminSetVariable() (*Command, error) { p.nextToken() // consume VAR varName, err := p.parseIdentifier() if err != nil { return nil, err } p.nextToken() varValue, err := p.parseVariableValue() if err != nil { return nil, err } cmd := NewCommand("set_variable") cmd.Params["var_name"] = varName cmd.Params["var_value"] = varValue p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminSetDefault() (*Command, error) { p.nextToken() // consume DEFAULT var modelType string switch p.curToken.Type { case TokenChat: modelType = "chat" case TokenVision: modelType = "vision" case TokenEmbedding: modelType = "embedding" case TokenRerank: modelType = "rerank" case TokenASR: modelType = "asr" case TokenTTS: modelType = "tts" case TokenOCR: modelType = "ocr" default: return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value) } p.nextToken() modelNameOrID, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("set_default_model") cmd.Params["model_type"] = modelType 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) } p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminSetToken() (*Command, error) { p.nextToken() // consume TOKEN tokenValue, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("set_token") cmd.Params["token"] = tokenValue p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminResetCommand() (*Command, error) { p.nextToken() // consume RESET if p.curToken.Type != TokenDefault { return nil, fmt.Errorf("expected DEFAULT") } p.nextToken() var modelType string switch p.curToken.Type { case TokenChat: modelType = "chat" case TokenVision: modelType = "vision" case TokenEmbedding: modelType = "embedding" case TokenRerank: modelType = "rerank" case TokenASR: modelType = "asr" case TokenTTS: modelType = "tts" case TokenOCR: modelType = "ocr" default: return nil, fmt.Errorf("unknown model type: %s", p.curToken.Value) } cmd := NewCommand("reset_default_model") cmd.Params["model_type"] = modelType p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminGenerateCommand() (*Command, error) { p.nextToken() // consume GENERATE if p.curToken.Type != TokenToken { return nil, fmt.Errorf("expected TOKEN") } p.nextToken() if p.curToken.Type != TokenFor { return nil, fmt.Errorf("expected FOR") } p.nextToken() if p.curToken.Type != TokenUser { return nil, fmt.Errorf("expected USER") } p.nextToken() userName, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("generate_token") cmd.Params["user_name"] = userName p.nextToken() // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminImportCommand() (*Command, error) { p.nextToken() // consume IMPORT documentPaths, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() if p.curToken.Type != TokenInto { return nil, fmt.Errorf("expected INTO") } 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("import_docs_into_dataset") cmd.Params["document_paths"] = documentPaths cmd.Params["dataset_name"] = datasetName p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRetrieveCommand() (*Command, error) { p.nextToken() // consume SEARCH question, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() if p.curToken.Type != TokenOn { return nil, fmt.Errorf("expected ON") } p.nextToken() if p.curToken.Type != TokenDatasets { return nil, fmt.Errorf("expected DATASETS") } p.nextToken() datasets, err := p.parseQuotedString() if err != nil { return nil, err } cmd := NewCommand("search_on_datasets") cmd.Params["question"] = question cmd.Params["datasets"] = datasets p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminParseCommand() (*Command, error) { p.nextToken() // consume PARSE if p.curToken.Type == TokenDataset { return p.parseParseDataset() } return p.parseParseDocs() } func (p *Parser) parseAdminParseDataset() (*Command, error) { p.nextToken() // consume DATASET datasetName, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() var method string if p.curToken.Type == TokenSync { method = "sync" } else if p.curToken.Type == TokenAsync { method = "async" } else { return nil, fmt.Errorf("expected SYNC or ASYNC") } cmd := NewCommand("parse_dataset") cmd.Params["dataset_name"] = datasetName cmd.Params["method"] = method p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminParseDocs() (*Command, error) { documentNames, err := p.parseQuotedString() if err != nil { return nil, err } p.nextToken() 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("parse_dataset_docs") cmd.Params["document_names"] = documentNames cmd.Params["dataset_name"] = datasetName p.nextToken() // Semicolon is optional for UNSET TOKEN 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() case TokenRetrieve: return p.parseRetrieveCommand() default: return nil, fmt.Errorf("invalid user statement: %s", p.curToken.Value) } } func (p *Parser) parseAdminStartupCommand() (*Command, error) { p.nextToken() // consume STARTUP if p.curToken.Type != TokenService { return nil, fmt.Errorf("expected SERVICE") } p.nextToken() serviceNum, err := p.parseNumber() if err != nil { return nil, err } cmd := NewCommand("startup_service") cmd.Params["number"] = serviceNum p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShutdownCommand() (*Command, error) { p.nextToken() // consume SHUTDOWN switch p.curToken.Type { case TokenService: return p.parseAdminShutdownServiceCommand() case TokenIngestor: return p.parseAdminShutdownIngestorCommand() default: return nil, fmt.Errorf("expected SERVICE or INGESTOR") } } func (p *Parser) parseAdminShutdownServiceCommand() (*Command, error) { p.nextToken() // consume SERVICE serviceNum, err := p.parseNumber() if err != nil { return nil, err } cmd := NewCommand("shutdown_service") cmd.Params["number"] = serviceNum p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminShutdownIngestorCommand() (*Command, error) { 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() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminRestartCommand() (*Command, error) { p.nextToken() // consume RESTART if p.curToken.Type != TokenService { return nil, fmt.Errorf("expected SERVICE") } p.nextToken() serviceNum, err := p.parseNumber() if err != nil { return nil, err } cmd := NewCommand("restart_service") cmd.Params["number"] = serviceNum p.nextToken() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } func (p *Parser) parseAdminAddCommand() (*Command, error) { p.nextToken() // consume ADD switch p.curToken.Type { case TokenAPI: return p.parseAddAPIServer() case TokenAdmin: return p.parseAddAdminServer() default: return nil, fmt.Errorf("unknown ADD target: %s", p.curToken.Value) } } func (p *Parser) parseAdminDeleteCommand() (*Command, error) { p.nextToken() // consume DELETE switch p.curToken.Type { case TokenAPI: return p.parseDeleteAPIServer() case TokenAdmin: return p.parseDeleteAdminServer() default: return nil, fmt.Errorf("unknown ADD target: %s", p.curToken.Value) } } 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) } } 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") } } 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() // Semicolon is optional for UNSET TOKEN 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() // Semicolon is optional for UNSET TOKEN 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() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } 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() // Semicolon is optional for UNSET TOKEN if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("unset_token"), nil } 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 } func (p *Parser) parseAdminRemoveCommand() (*Command, error) { p.nextToken() // consume MESSAGE_QUEUE var cmd *Command switch p.curToken.Type { case TokenService: p.nextToken() // consume SERVICE serviceNum, err := p.parseNumber() if err != nil { return nil, fmt.Errorf("expected service number after SERVICE") } p.nextToken() // consume service number cmd = NewCommand("admin_remove_service_command") cmd.Params["service_number"] = serviceNum case TokenIngestion: return p.parseAdminRemoveIngestionTasks() case TokenUser: return p.parseAdminRemoveUserCommand() default: return nil, fmt.Errorf("expected SERVICE") } // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } // SHOW VERSION; func (p *Parser) parseAdminShowVersionCommand() (*Command, error) { p.nextToken() // consume VERSION // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("show_version"), nil } // SHOW CURRENT; func (p *Parser) parseAdminShowCurrentCommand() (*Command, error) { p.nextToken() // consume CURRENT // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return NewCommand("show_current"), nil } // SHOW USER 'user@example.com'; // SHOW USER 'user@example.com' DATASET 'dataset_name'; // SHOW USER 'user@example.com' SUMMARY; // SHOW USER 'user@example.com' STORAGE; // SHOW USER 'user@example.com' QUOTA; // SHOW USER 'user@example.com' INDEX; func (p *Parser) parseAdminShowUserCommand() (*Command, error) { p.nextToken() // consume USER 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.parseAdminShowUserInfoCommand(userName) } } // SHOW USER 'user@example.com'; func (p *Parser) parseAdminShowUserInfoCommand(userName string) (*Command, error) { // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } cmd := NewCommand("admin_show_user_info_command") 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() if err != nil { return nil, err } if days < 1 { return nil, fmt.Errorf("invalid number of DAYS") } p.nextToken() } else { days = 7 } // 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() if err != nil { return nil, err } p.nextToken() if p.curToken.Type == TokenTree { tree = true p.nextToken() } cmd := NewCommand("admin_show_user_dataset_command") cmd.Params["user_name"] = userName if datasetName != "" { cmd.Params["dataset_name"] = datasetName } if tree { cmd.Params["tree"] = true } // 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 if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } // 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 USERS SUMMARY; // SHOW USERS ACTIVITY; func (p *Parser) parseAdminShowUsersCommand() (*Command, error) { p.nextToken() // consume USERS switch p.curToken.Type { case TokenSummary: p.nextToken() cmd := NewCommand("admin_show_users_summary_command") return cmd, nil case TokenActivity: return p.parseAdminShowUsersActivityCommand() default: return nil, fmt.Errorf("invalid command") } } // SHOW USERS ACTIVITY WINDOW 2 DAYS 30; func (p *Parser) parseAdminShowUsersActivityCommand() (*Command, error) { 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; func (p *Parser) parseAdminShowDataCommand() (*Command, error) { p.nextToken() // consume ALL var cmd *Command switch p.curToken.Type { case TokenSummary: p.nextToken() cmd = NewCommand("admin_show_data_summary_command") case TokenOrphan: p.nextToken() cmd = NewCommand("admin_show_data_orphan_command") case TokenStorage: p.nextToken() cmd = NewCommand("admin_show_data_storage_command") case TokenIndex: p.nextToken() cmd = NewCommand("admin_show_data_index_command") default: return nil, fmt.Errorf("expected SUMMARY, ORPHAN, STORAGE, INDEX, TASKS, QUOTA_SUMMARY after ALL") } // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } // SHOW QUOTA SUMMARY; func (p *Parser) parseAdminShowQuotaCommand() (*Command, error) { p.nextToken() // consume QUOTA var cmd *Command switch p.curToken.Type { case TokenSummary: p.nextToken() cmd = NewCommand("admin_show_quota_summary_command") default: return nil, fmt.Errorf("expected SUMMARY after QUOTA") } // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } // SHOW TASKS SUMMARY; func (p *Parser) parseAdminShowTasksCommand() (*Command, error) { p.nextToken() // consume TASKS var cmd *Command switch p.curToken.Type { case TokenSummary: p.nextToken() cmd = NewCommand("admin_show_tasks_summary_command") default: return nil, fmt.Errorf("expected SUMMARY after TASKS") } // Semicolon is optional if p.curToken.Type == TokenSemicolon { p.nextToken() } return cmd, nil } // 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 } // LIST USER 'user@example.com' INGESTION TASKS; 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: p.nextToken() if p.curToken.Type != TokenTasks { return nil, fmt.Errorf("expected TASKS after INGESTION") } p.nextToken() cmd = NewCommand("admin_list_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 } // 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 }