Skip to content

Commit

Permalink
Add support for CREATE, UPDATE, DROP skill
Browse files Browse the repository at this point in the history
  • Loading branch information
tmichaeldb committed Oct 27, 2023
1 parent 97f0bc7 commit 529568f
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 0 deletions.
1 change: 1 addition & 0 deletions mindsdb_sql/parser/dialects/mindsdb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions mindsdb_sql/parser/dialects/mindsdb/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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'
Expand Down
23 changes: 23 additions & 0 deletions mindsdb_sql/parser/dialects/mindsdb/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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):
Expand Down
93 changes: 93 additions & 0 deletions mindsdb_sql/parser/dialects/mindsdb/skills.py
Original file line number Diff line number Diff line change
@@ -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
49 changes: 49 additions & 0 deletions tests/test_parser/test_mindsdb/test_skills.py
Original file line number Diff line number Diff line change
@@ -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()

0 comments on commit 529568f

Please sign in to comment.