From 529568fa656eb13aa2a8702787c1ab95ae57ba0e Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Thu, 26 Oct 2023 17:11:43 -0700 Subject: [PATCH 1/8] Add support for CREATE, UPDATE, DROP skill --- .../parser/dialects/mindsdb/__init__.py | 1 + mindsdb_sql/parser/dialects/mindsdb/lexer.py | 2 + mindsdb_sql/parser/dialects/mindsdb/parser.py | 23 +++++ mindsdb_sql/parser/dialects/mindsdb/skills.py | 93 +++++++++++++++++++ tests/test_parser/test_mindsdb/test_skills.py | 49 ++++++++++ 5 files changed, 168 insertions(+) create mode 100644 mindsdb_sql/parser/dialects/mindsdb/skills.py create mode 100644 tests/test_parser/test_mindsdb/test_skills.py diff --git a/mindsdb_sql/parser/dialects/mindsdb/__init__.py b/mindsdb_sql/parser/dialects/mindsdb/__init__.py index 4ab0a9dd..d7e5d4ba 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/__init__.py +++ b/mindsdb_sql/parser/dialects/mindsdb/__init__.py @@ -16,6 +16,7 @@ from .chatbot import CreateChatBot, UpdateChatBot, DropChatBot from .trigger import CreateTrigger, DropTrigger from .knowledge_base import CreateKnowledgeBase, DropKnowledgeBase +from .skills import CreateSkill, DropSkill, UpdateSkill # remove it in next release CreateDatasource = CreateDatabase diff --git a/mindsdb_sql/parser/dialects/mindsdb/lexer.py b/mindsdb_sql/parser/dialects/mindsdb/lexer.py index 19c200ee..74780f3b 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/lexer.py +++ b/mindsdb_sql/parser/dialects/mindsdb/lexer.py @@ -31,6 +31,7 @@ class MindsDBLexer(Lexer): ENGINE, TRAIN, PREDICT, PARAMETERS, JOB, CHATBOT, EVERY,PROJECT, ANOMALY, DETECTION, KNOWLEDGE_BASE, KNOWLEDGE_BASES, + SKILL, # SHOW/DDL Keywords @@ -119,6 +120,7 @@ class MindsDBLexer(Lexer): KNOWLEDGE_BASE = r'\bKNOWLEDGE[_|\s]BASE\b' KNOWLEDGE_BASES = r'\bKNOWLEDGE[_|\s]BASES\b' + SKILL = r'\bSKILL\b' # Misc SET = r'\bSET\b' diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index bd9799dd..2537dd84 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -17,6 +17,7 @@ from mindsdb_sql.parser.dialects.mindsdb.evaluate import Evaluate from mindsdb_sql.parser.dialects.mindsdb.create_file import CreateFile from mindsdb_sql.parser.dialects.mindsdb.knowledge_base import CreateKnowledgeBase, DropKnowledgeBase +from mindsdb_sql.parser.dialects.mindsdb.skills import CreateSkill, DropSkill, UpdateSkill from mindsdb_sql.exceptions import ParsingException from mindsdb_sql.parser.dialects.mindsdb.lexer import MindsDBLexer from mindsdb_sql.parser.dialects.mindsdb.retrain_predictor import RetrainPredictor @@ -85,6 +86,9 @@ class MindsDBParser(Parser): 'drop_trigger', 'create_kb', 'drop_kb', + 'create_skill', + 'drop_skill', + 'update_skill' ) def query(self, p): return p[0] @@ -130,6 +134,25 @@ def create_kb(self, p): def drop_kb(self, p): return DropKnowledgeBase(name=p.identifier, if_exists=p.if_exists_or_empty) + # -- Skills -- + @_('CREATE SKILL if_not_exists_or_empty identifier USING kw_parameter_list') + def create_skill(self, p): + params = p.kw_parameter_list + + return CreateSkill( + name=p.identifier, + type=params.pop('type'), + params=params + ) + + @_('DROP SKILL if_exists_or_empty identifier') + def drop_skill(self, p): + return DropSkill(name=p.identifier, if_exists=p.if_exists_or_empty) + + @_('UPDATE SKILL identifier SET kw_parameter_list') + def update_skill(self, p): + return UpdateSkill(name=p.identifier, updated_params=p.kw_parameter_list) + # -- ChatBot -- @_('CREATE CHATBOT identifier USING kw_parameter_list') def create_chat_bot(self, p): diff --git a/mindsdb_sql/parser/dialects/mindsdb/skills.py b/mindsdb_sql/parser/dialects/mindsdb/skills.py new file mode 100644 index 00000000..91bb3bff --- /dev/null +++ b/mindsdb_sql/parser/dialects/mindsdb/skills.py @@ -0,0 +1,93 @@ +from mindsdb_sql.parser.ast.base import ASTNode +from mindsdb_sql.parser.utils import indent + + +class CreateSkill(ASTNode): + """ + Node for creating a new skill + """ + + def __init__(self, name, type, params, if_not_exists=False, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the skill to create + type (str): type of the skill to create + params (dict): USING parameters to create the skill with + if_not_exists (bool): if True, do not raise an error if the skill exists + """ + super().__init__(*args, **kwargs) + self.name = name + self.type = type + self.params = params + self.if_not_exists = if_not_exists + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}CreateSkill(' \ + f'if_not_exists={self.if_not_exists}' \ + f'name={self.name.to_string()}, ' \ + f'type={self.type}, ' \ + f'params={self.params})' + return out_str + + def get_string(self, *args, **kwargs): + using_ar = [f'{k}={repr(v)}' for k, v in self.params.items()] + using_str = ', '.join(using_ar) + + out_str = f'CREATE SKILL {"IF NOT EXISTS" if self.if_not_exists else ""}{self.name.to_string()} USING {using_str}' + return out_str + + +class UpdateSkill(ASTNode): + """ + Node for updating a skill + """ + + def __init__(self, name, updated_params, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the skill to update + updated_params (dict): new SET parameters of the skill to update + """ + super().__init__(*args, **kwargs) + self.name = name + self.params = updated_params + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}UpdateSkill(' \ + f'name={self.name.to_string()}, ' \ + f'updated_params={self.params})' + return out_str + + def get_string(self, *args, **kwargs): + set_ar = [f'{k}={repr(v)}' for k, v in self.params.items()] + set_str = ', '.join(set_ar) + + out_str = f'UPDATE SKILL {self.name.to_string()} SET {set_str}' + return out_str + + +class DropSkill(ASTNode): + """ + Node for dropping a skill + """ + + def __init__(self, name, if_exists=False, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the skill to drop + if_exists (bool): if True, do not raise an error if the skill does not exist + """ + super().__init__(*args, **kwargs) + self.name = name + self.if_exists = if_exists + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}DropSkill(if_exists={self.if_exists}, name={self.name.to_string()})' + return out_str + + def get_string(self, *args, **kwargs): + out_str = f'DROP SKILL {"IF EXISTS" if self.if_exists else ""}{str(self.name.to_string())}' + return out_str diff --git a/tests/test_parser/test_mindsdb/test_skills.py b/tests/test_parser/test_mindsdb/test_skills.py new file mode 100644 index 00000000..1e73a73d --- /dev/null +++ b/tests/test_parser/test_mindsdb/test_skills.py @@ -0,0 +1,49 @@ +from mindsdb_sql import parse_sql +from mindsdb_sql.parser.dialects.mindsdb import * +from mindsdb_sql.parser.ast import * + + +class TestSkills: + def test_create_skill(self): + sql = ''' + create skill my_skill + using + type = 'knowledge_base', + source ='my_knowledge_base' + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_ast = CreateSkill( + name=Identifier('my_skill'), + type='knowledge_base', + params={'source': 'my_knowledge_base'} + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() + + def test_update_skill(self): + sql = ''' + update skill my_skill + set + source = 'new_source' + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_params = { + 'source': 'new_source' + } + expected_ast = UpdateSkill( + name=Identifier('my_skill'), + updated_params=expected_params + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() + + def test_drop_skill(self): + sql = ''' + drop skill my_skill + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_ast = DropSkill( + name=Identifier('my_skill'), + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() From 69ddf1c2d196f1ab3bcbde9966750da479374835 Mon Sep 17 00:00:00 2001 From: Zoran Pandovski Date: Tue, 31 Oct 2023 11:41:11 +0100 Subject: [PATCH 2/8] Delete SECURITY.md --- SECURITY.md | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 384833dc..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,33 +0,0 @@ -# MindsDB Security Policy - -At MindsDB, we consider the security of our systems a top priority. However, no matter how much effort we put into system security, there can still be vulnerabilities present. -Supported Versions - -## Supported Versions for MindsDB_SQL - -Use this section to tell people about which versions of your project are -currently being supported with security updates. - -| Version | Supported | -| ------- | ------------------ | -| >= v0.0.44 | :white_check_mark: | - -### Reporting a Vulnerability - -If you discover a security vulnerability, we appreciate your efforts. In order to responsibly disclose your findings of security concerns you suggest sending an email to hello@mindsdb.com, providing as much detail as you can with the name of the repository. Please do not publicly disclose these details without express consent from us. - -Upon receiving your email, our security team will assess and respond to your report. We strive to keep all communication channels open with you to address your report effectively. -Disclosure Policy - -Once we have received and evaluated your vulnerability report, MindsDB commits to: - -* Confirm the receipt of your report -* Assess the vulnerability report to confirm its validity -* Work on a fix and update the impacted versions -* Publicly disclose the vulnerability after it has been addressed, giving credit to the reporter if they wish - -### Comments on this Policy - -If you have any suggestions to improve this policy, please don't hesitate to let us know. We are committed to ensuring that our approach works effectively for everyone involved. - -Thank you for helping to make MindsDB safer for everyone. From 66837ca7e7664edbd1ed2639281d318d27929f79 Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Tue, 31 Oct 2023 15:16:28 -0700 Subject: [PATCH 3/8] Fixed "if not exists" for create skill --- mindsdb_sql/parser/dialects/mindsdb/parser.py | 3 ++- mindsdb_sql/parser/dialects/mindsdb/skills.py | 7 ++++--- tests/test_parser/test_mindsdb/test_skills.py | 21 +++++++++++++++---- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index 2537dd84..99530df6 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -142,7 +142,8 @@ def create_skill(self, p): return CreateSkill( name=p.identifier, type=params.pop('type'), - params=params + params=params, + if_not_exists=p.if_not_exists_or_empty ) @_('DROP SKILL if_exists_or_empty identifier') diff --git a/mindsdb_sql/parser/dialects/mindsdb/skills.py b/mindsdb_sql/parser/dialects/mindsdb/skills.py index 91bb3bff..2a03d2bd 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/skills.py +++ b/mindsdb_sql/parser/dialects/mindsdb/skills.py @@ -31,10 +31,11 @@ def to_tree(self, level=0, *args, **kwargs): return out_str def get_string(self, *args, **kwargs): - using_ar = [f'{k}={repr(v)}' for k, v in self.params.items()] + using_ar = [f'type={repr(self.type)}'] + using_ar += [f'{k}={repr(v)}' for k, v in self.params.items()] using_str = ', '.join(using_ar) - out_str = f'CREATE SKILL {"IF NOT EXISTS" if self.if_not_exists else ""}{self.name.to_string()} USING {using_str}' + out_str = f'CREATE SKILL {"IF NOT EXISTS " if self.if_not_exists else ""}{self.name.to_string()} USING {using_str}' return out_str @@ -89,5 +90,5 @@ def to_tree(self, level=0, *args, **kwargs): return out_str def get_string(self, *args, **kwargs): - out_str = f'DROP SKILL {"IF EXISTS" if self.if_exists else ""}{str(self.name.to_string())}' + out_str = f'DROP SKILL {"IF EXISTS " if self.if_exists else ""}{str(self.name.to_string())}' return out_str diff --git a/tests/test_parser/test_mindsdb/test_skills.py b/tests/test_parser/test_mindsdb/test_skills.py index 1e73a73d..b79a4faf 100644 --- a/tests/test_parser/test_mindsdb/test_skills.py +++ b/tests/test_parser/test_mindsdb/test_skills.py @@ -6,7 +6,7 @@ class TestSkills: def test_create_skill(self): sql = ''' - create skill my_skill + create skill if not exists my_skill using type = 'knowledge_base', source ='my_knowledge_base' @@ -15,10 +15,15 @@ def test_create_skill(self): expected_ast = CreateSkill( name=Identifier('my_skill'), type='knowledge_base', - params={'source': 'my_knowledge_base'} + params={'source': 'my_knowledge_base'}, + if_not_exists=True ) assert str(ast) == str(expected_ast) assert ast.to_tree() == expected_ast.to_tree() + + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) def test_update_skill(self): sql = ''' @@ -37,13 +42,21 @@ def test_update_skill(self): assert str(ast) == str(expected_ast) assert ast.to_tree() == expected_ast.to_tree() + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) + def test_drop_skill(self): sql = ''' - drop skill my_skill + drop skill if exists my_skill ''' ast = parse_sql(sql, dialect='mindsdb') expected_ast = DropSkill( - name=Identifier('my_skill'), + name=Identifier('my_skill'), if_exists=True ) assert str(ast) == str(expected_ast) assert ast.to_tree() == expected_ast.to_tree() + + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) From b403486bcac158dd514a94506083b2d485fdf937 Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Tue, 31 Oct 2023 16:53:01 -0700 Subject: [PATCH 4/8] Add SQL Support for Agents --- .../parser/dialects/mindsdb/__init__.py | 1 + mindsdb_sql/parser/dialects/mindsdb/agents.py | 94 +++++++++++++++++++ mindsdb_sql/parser/dialects/mindsdb/lexer.py | 2 + mindsdb_sql/parser/dialects/mindsdb/parser.py | 26 ++++- tests/test_parser/test_mindsdb/test_agents.py | 64 +++++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 mindsdb_sql/parser/dialects/mindsdb/agents.py create mode 100644 tests/test_parser/test_mindsdb/test_agents.py diff --git a/mindsdb_sql/parser/dialects/mindsdb/__init__.py b/mindsdb_sql/parser/dialects/mindsdb/__init__.py index d7e5d4ba..aa26ef4b 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/__init__.py +++ b/mindsdb_sql/parser/dialects/mindsdb/__init__.py @@ -1,3 +1,4 @@ +from .agents import CreateAgent, DropAgent, UpdateAgent from .create_view import CreateView from .create_database import CreateDatabase from .create_predictor import CreatePredictor, CreateAnomalyDetectionModel diff --git a/mindsdb_sql/parser/dialects/mindsdb/agents.py b/mindsdb_sql/parser/dialects/mindsdb/agents.py new file mode 100644 index 00000000..ee96686e --- /dev/null +++ b/mindsdb_sql/parser/dialects/mindsdb/agents.py @@ -0,0 +1,94 @@ +from mindsdb_sql.parser.ast.base import ASTNode +from mindsdb_sql.parser.utils import indent + + +class CreateAgent(ASTNode): + """ + Node for creating a new agent + """ + + def __init__(self, name, model, params, if_not_exists=False, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the agent to create + model (str): name of the underlying model to use with the agent + params (dict): USING parameters to create the agent with + if_not_exists (bool): if True, do not raise an error if the agent exists + """ + super().__init__(*args, **kwargs) + self.name = name + self.model = model + self.params = params + self.if_not_exists = if_not_exists + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}CreateAgent(' \ + f'if_not_exists={self.if_not_exists}' \ + f'name={self.name.to_string()}, ' \ + f'model={self.model}, ' \ + f'params={self.params})' + return out_str + + def get_string(self, *args, **kwargs): + using_ar = [f'model={repr(self.model)}'] + using_ar += [f'{k}={repr(v)}' for k, v in self.params.items()] + using_str = ', '.join(using_ar) + + out_str = f'CREATE AGENT {"IF NOT EXISTS " if self.if_not_exists else ""}{self.name.to_string()} USING {using_str}' + return out_str + + +class UpdateAgent(ASTNode): + """ + Node for updating an agent + """ + + def __init__(self, name, updated_params, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the agent to update + updated_params (dict): new SET parameters of the agent to update + """ + super().__init__(*args, **kwargs) + self.name = name + self.params = updated_params + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}UpdateAgent(' \ + f'name={self.name.to_string()}, ' \ + f'updated_params={self.params})' + return out_str + + def get_string(self, *args, **kwargs): + set_ar = [f'{k}={repr(v)}' for k, v in self.params.items()] + set_str = ', '.join(set_ar) + + out_str = f'UPDATE AGENT {self.name.to_string()} SET {set_str}' + return out_str + + +class DropAgent(ASTNode): + """ + Node for dropping an agent + """ + + def __init__(self, name, if_exists=False, *args, **kwargs): + """ + Parameters: + name (Identifier): name of the agent to drop + if_exists (bool): if True, do not raise an error if the agent does not exist + """ + super().__init__(*args, **kwargs) + self.name = name + self.if_exists = if_exists + + def to_tree(self, level=0, *args, **kwargs): + ind = indent(level) + out_str = f'{ind}DropAgent(if_exists={self.if_exists}, name={self.name.to_string()})' + return out_str + + def get_string(self, *args, **kwargs): + out_str = f'DROP AGENT {"IF EXISTS " if self.if_exists else ""}{str(self.name.to_string())}' + return out_str diff --git a/mindsdb_sql/parser/dialects/mindsdb/lexer.py b/mindsdb_sql/parser/dialects/mindsdb/lexer.py index 74780f3b..752dddaf 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/lexer.py +++ b/mindsdb_sql/parser/dialects/mindsdb/lexer.py @@ -32,6 +32,7 @@ class MindsDBLexer(Lexer): ANOMALY, DETECTION, KNOWLEDGE_BASE, KNOWLEDGE_BASES, SKILL, + AGENT, # SHOW/DDL Keywords @@ -121,6 +122,7 @@ class MindsDBLexer(Lexer): KNOWLEDGE_BASE = r'\bKNOWLEDGE[_|\s]BASE\b' KNOWLEDGE_BASES = r'\bKNOWLEDGE[_|\s]BASES\b' SKILL = r'\bSKILL\b' + AGENT = r'\bAGENT\b' # Misc SET = r'\bSET\b' diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index 99530df6..91fabcde 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -1,6 +1,7 @@ from sly import Parser from mindsdb_sql.parser.ast import * from mindsdb_sql.parser.ast.drop import DropDatabase, DropView +from mindsdb_sql.parser.dialects.mindsdb.agents import CreateAgent, DropAgent, UpdateAgent from mindsdb_sql.parser.dialects.mindsdb.drop_datasource import DropDatasource from mindsdb_sql.parser.dialects.mindsdb.drop_predictor import DropPredictor from mindsdb_sql.parser.dialects.mindsdb.drop_dataset import DropDataset @@ -88,7 +89,10 @@ class MindsDBParser(Parser): 'drop_kb', 'create_skill', 'drop_skill', - 'update_skill' + 'update_skill', + 'create_agent', + 'drop_agent', + 'update_agent' ) def query(self, p): return p[0] @@ -154,6 +158,26 @@ def drop_skill(self, p): def update_skill(self, p): return UpdateSkill(name=p.identifier, updated_params=p.kw_parameter_list) + # -- Agent -- + @_('CREATE AGENT if_not_exists_or_empty identifier USING kw_parameter_list') + def create_agent(self, p): + params = p.kw_parameter_list + + return CreateAgent( + name=p.identifier, + model=params.pop('model'), + params=params, + if_not_exists=p.if_not_exists_or_empty + ) + + @_('DROP AGENT if_exists_or_empty identifier') + def drop_agent(self, p): + return DropAgent(name=p.identifier, if_exists=p.if_exists_or_empty) + + @_('UPDATE AGENT identifier SET kw_parameter_list') + def update_agent(self, p): + return UpdateAgent(name=p.identifier, updated_params=p.kw_parameter_list) + # -- ChatBot -- @_('CREATE CHATBOT identifier USING kw_parameter_list') def create_chat_bot(self, p): diff --git a/tests/test_parser/test_mindsdb/test_agents.py b/tests/test_parser/test_mindsdb/test_agents.py new file mode 100644 index 00000000..4c6537bf --- /dev/null +++ b/tests/test_parser/test_mindsdb/test_agents.py @@ -0,0 +1,64 @@ +from mindsdb_sql import parse_sql +from mindsdb_sql.parser.dialects.mindsdb import * +from mindsdb_sql.parser.ast import * + + +class TestAgents: + def test_create_agent(self): + sql = ''' + create agent if not exists my_agent + using + model = 'my_model', + skills = ['skill1', 'skill2'] + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_ast = CreateAgent( + name=Identifier('my_agent'), + model='my_model', + params={'skills': ['skill1', 'skill2']}, + if_not_exists=True + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() + + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) + + def test_update_agent(self): + sql = ''' + update agent my_agent + set + model = 'new_model', + skills = ['new_skill1', 'new_skill2'] + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_params = { + 'model': 'new_model', + 'skills': ['new_skill1', 'new_skill2'] + } + expected_ast = UpdateAgent( + name=Identifier('my_agent'), + updated_params=expected_params + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() + + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) + + def test_drop_agent(self): + sql = ''' + drop agent if exists my_agent + ''' + ast = parse_sql(sql, dialect='mindsdb') + expected_ast = DropAgent( + name=Identifier('my_agent'), if_exists=True + ) + assert str(ast) == str(expected_ast) + assert ast.to_tree() == expected_ast.to_tree() + + # Parse again after rendering to catch problems with rendering. + ast = parse_sql(str(ast), dialect='mindsdb') + assert str(ast) == str(expected_ast) From f67a1739c09ba5ad65354a3ae194ba97664c0c8f Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 1 Nov 2023 18:31:36 +0300 Subject: [PATCH 5/8] bump version --- mindsdb_sql/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mindsdb_sql/__about__.py b/mindsdb_sql/__about__.py index 268ba066..a960e8d4 100644 --- a/mindsdb_sql/__about__.py +++ b/mindsdb_sql/__about__.py @@ -1,6 +1,6 @@ __title__ = 'mindsdb_sql' __package_name__ = 'mindsdb_sql' -__version__ = '0.7.3' +__version__ = '0.7.4' __description__ = "Pure python SQL parser" __email__ = "jorge@mindsdb.com" __author__ = 'MindsDB Inc' From 686224050265f19cc526ba25d931a25585e0e38b Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Wed, 1 Nov 2023 13:43:38 -0700 Subject: [PATCH 6/8] agent -> agent_name in CHATBOT commands --- mindsdb_sql/parser/dialects/mindsdb/chatbot.py | 4 ++-- mindsdb_sql/parser/dialects/mindsdb/parser.py | 2 +- tests/test_parser/test_mindsdb/test_chatbots.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mindsdb_sql/parser/dialects/mindsdb/chatbot.py b/mindsdb_sql/parser/dialects/mindsdb/chatbot.py index f3366b80..d64e8d38 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/chatbot.py +++ b/mindsdb_sql/parser/dialects/mindsdb/chatbot.py @@ -30,7 +30,7 @@ def to_tree(self, *args, level=0, **kwargs): f'name={self.name.to_string()}, ' \ f'database={self.database.to_string()}, ' \ f'model={model_str}, ' \ - f'agent={agent_str}, ' \ + f'agent_name={agent_str}, ' \ f'params={self.params})' return out_str @@ -39,7 +39,7 @@ def get_string(self, *args, **kwargs): params = self.params.copy() params['model'] = self.model.to_string() if self.model else 'NULL' params['database'] = self.database.to_string() - params['agent'] = self.agent.to_string() if self.agent else 'NULL' + params['agent_name'] = self.agent.to_string() if self.agent else 'NULL' using_ar = [f'{k}={repr(v)}' for k, v in params.items()] diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index 91fabcde..17edb101 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -185,7 +185,7 @@ def create_chat_bot(self, p): database = Identifier(params.pop('database')) model_param = params.pop('model', None) - agent_param = params.pop('agent', None) + agent_param = params.pop('agent_name', None) model = Identifier( model_param) if model_param is not None else None agent = Identifier( diff --git a/tests/test_parser/test_mindsdb/test_chatbots.py b/tests/test_parser/test_mindsdb/test_chatbots.py index 99e3aa2d..4a2ace25 100644 --- a/tests/test_parser/test_mindsdb/test_chatbots.py +++ b/tests/test_parser/test_mindsdb/test_chatbots.py @@ -10,7 +10,7 @@ def test_test_create_chatbot(self): using model = 'chat_model', database ='my_rocket_chat', - agent = 'my_agent' + agent_name = 'my_agent' ''' ast = parse_sql(sql, dialect='mindsdb') expected_ast = CreateChatBot( From 6be7aeae8f39c675984d1026ae690d5fdaa77676 Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Wed, 1 Nov 2023 13:49:38 -0700 Subject: [PATCH 7/8] Revert change to agent_name --- mindsdb_sql/parser/dialects/mindsdb/chatbot.py | 4 ++-- mindsdb_sql/parser/dialects/mindsdb/parser.py | 2 +- tests/test_parser/test_mindsdb/test_chatbots.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mindsdb_sql/parser/dialects/mindsdb/chatbot.py b/mindsdb_sql/parser/dialects/mindsdb/chatbot.py index d64e8d38..f3366b80 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/chatbot.py +++ b/mindsdb_sql/parser/dialects/mindsdb/chatbot.py @@ -30,7 +30,7 @@ def to_tree(self, *args, level=0, **kwargs): f'name={self.name.to_string()}, ' \ f'database={self.database.to_string()}, ' \ f'model={model_str}, ' \ - f'agent_name={agent_str}, ' \ + f'agent={agent_str}, ' \ f'params={self.params})' return out_str @@ -39,7 +39,7 @@ def get_string(self, *args, **kwargs): params = self.params.copy() params['model'] = self.model.to_string() if self.model else 'NULL' params['database'] = self.database.to_string() - params['agent_name'] = self.agent.to_string() if self.agent else 'NULL' + params['agent'] = self.agent.to_string() if self.agent else 'NULL' using_ar = [f'{k}={repr(v)}' for k, v in params.items()] diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index 17edb101..91fabcde 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -185,7 +185,7 @@ def create_chat_bot(self, p): database = Identifier(params.pop('database')) model_param = params.pop('model', None) - agent_param = params.pop('agent_name', None) + agent_param = params.pop('agent', None) model = Identifier( model_param) if model_param is not None else None agent = Identifier( diff --git a/tests/test_parser/test_mindsdb/test_chatbots.py b/tests/test_parser/test_mindsdb/test_chatbots.py index 4a2ace25..99e3aa2d 100644 --- a/tests/test_parser/test_mindsdb/test_chatbots.py +++ b/tests/test_parser/test_mindsdb/test_chatbots.py @@ -10,7 +10,7 @@ def test_test_create_chatbot(self): using model = 'chat_model', database ='my_rocket_chat', - agent_name = 'my_agent' + agent = 'my_agent' ''' ast = parse_sql(sql, dialect='mindsdb') expected_ast = CreateChatBot( From 587087fe973dde9dd0d18305f8cb52d2cc47a69d Mon Sep 17 00:00:00 2001 From: tmichaeldb Date: Thu, 2 Nov 2023 15:40:32 -0700 Subject: [PATCH 8/8] Add AGENT as parser identifier --- mindsdb_sql/parser/dialects/mindsdb/parser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mindsdb_sql/parser/dialects/mindsdb/parser.py b/mindsdb_sql/parser/dialects/mindsdb/parser.py index 91fabcde..a2bfefe1 100644 --- a/mindsdb_sql/parser/dialects/mindsdb/parser.py +++ b/mindsdb_sql/parser/dialects/mindsdb/parser.py @@ -1657,6 +1657,7 @@ def parameter(self, p): 'WARNINGS', 'MODEL', 'MODELS', + 'AGENT' ) def id(self, p): return p[0]