mirror of https://github.com/apache/cassandra
Add missing cqlsh completion and round out cqlsh completion test coverage
IF (NOT) EXISTS is now also offered in cqlsh completion for CREATE TYPE, DROP TYPE, CREATE ROLE and DROP ROLE patch by Brad Schoening; reviewed by Stefan Miklosovic and Brandon Williams for CASSANDRA-16640
This commit is contained in:
parent
f236f40fc5
commit
addc5748a7
|
|
@ -1,4 +1,5 @@
|
|||
4.2
|
||||
* Offer IF (NOT) EXISTS in cqlsh completion for CREATE TYPE, DROP TYPE, CREATE ROLE and DROP ROLE (CASSANDRA-16640)
|
||||
* Nodetool bootstrap resume will now return an error if the operation fails (CASSANDRA-16491)
|
||||
* Disable resumable bootstrap by default (CASSANDRA-17679)
|
||||
* Include Git SHA in --verbose flag for nodetool version (CASSANDRA-17753)
|
||||
|
|
|
|||
|
|
@ -1313,7 +1313,7 @@ syntax_rules += r'''
|
|||
( "WITH" <cfamProperty> ( "AND" <cfamProperty> )* )?
|
||||
;
|
||||
|
||||
<createUserTypeStatement> ::= "CREATE" "TYPE" ( ks=<nonSystemKeyspaceName> dot="." )? typename=<cfOrKsName> "(" newcol=<cident> <storageType>
|
||||
<createUserTypeStatement> ::= "CREATE" "TYPE" ("IF" "NOT" "EXISTS")? ( ks=<nonSystemKeyspaceName> dot="." )? typename=<cfOrKsName> "(" newcol=<cident> <storageType>
|
||||
( "," [newcolname]=<cident> <storageType> )*
|
||||
")"
|
||||
;
|
||||
|
|
@ -1377,7 +1377,7 @@ syntax_rules += r'''
|
|||
<dropMaterializedViewStatement> ::= "DROP" "MATERIALIZED" "VIEW" ("IF" "EXISTS")? mv=<materializedViewName>
|
||||
;
|
||||
|
||||
<dropUserTypeStatement> ::= "DROP" "TYPE" ut=<userTypeName>
|
||||
<dropUserTypeStatement> ::= "DROP" "TYPE" ( "IF" "EXISTS" )? ut=<userTypeName>
|
||||
;
|
||||
|
||||
<dropFunctionStatement> ::= "DROP" "FUNCTION" ( "IF" "EXISTS" )? <userFunctionName>
|
||||
|
|
@ -1488,12 +1488,12 @@ syntax_rules += r'''
|
|||
| <unreservedKeyword>
|
||||
;
|
||||
|
||||
<createRoleStatement> ::= "CREATE" "ROLE" <rolename>
|
||||
<createRoleStatement> ::= "CREATE" "ROLE" ("IF" "NOT" "EXISTS")? <rolename>
|
||||
( "WITH" <roleProperty> ("AND" <roleProperty>)*)?
|
||||
;
|
||||
|
||||
<alterRoleStatement> ::= "ALTER" "ROLE" ("IF" "EXISTS")? <rolename>
|
||||
( "WITH" <roleProperty> ("AND" <roleProperty>)*)?
|
||||
( "WITH" <roleProperty> ("AND" <roleProperty>)*)
|
||||
;
|
||||
|
||||
<roleProperty> ::= (("HASHED")? "PASSWORD") "=" <stringLiteral>
|
||||
|
|
@ -1504,7 +1504,7 @@ syntax_rules += r'''
|
|||
| "ACCESS" "TO" "ALL" "DATACENTERS"
|
||||
;
|
||||
|
||||
<dropRoleStatement> ::= "DROP" "ROLE" <rolename>
|
||||
<dropRoleStatement> ::= "DROP" "ROLE" ("IF" "EXISTS")? <rolename>
|
||||
;
|
||||
|
||||
<grantRoleStatement> ::= "GRANT" <rolename> "TO" <rolename>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ cqlsh_source_cmd_syntax_rules = r'''
|
|||
'''
|
||||
|
||||
cqlsh_capture_cmd_syntax_rules = r'''
|
||||
<captureCommand> ::= "CAPTURE" ( fname=( <stringLiteral> | "OFF" ) )?
|
||||
<captureCommand> ::= "CAPTURE" ( fname=( <stringLiteral>) | "OFF" )?
|
||||
;
|
||||
'''
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ cqlsh_expand_cmd_syntax_rules = r'''
|
|||
'''
|
||||
|
||||
cqlsh_paging_cmd_syntax_rules = r'''
|
||||
<pagingCommand> ::= "PAGING" ( switch=( "ON" | "OFF" | /[0-9]+/) )?
|
||||
<pagingCommand> ::= "PAGING" ( switch=( "ON" | "OFF" | <wholenumber>) )?
|
||||
;
|
||||
'''
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ class CqlshCompletionCase(BaseTestCase):
|
|||
split_completed_lines=split_completed_lines)
|
||||
|
||||
if immediate:
|
||||
msg = 'cqlsh completed %r, but we expected %r' % (completed, immediate)
|
||||
msg = 'cqlsh completed %r (%d), but we expected %r (%d)' % (completed, len(completed), immediate, len(immediate))
|
||||
self.assertEqual(completed, immediate, msg=msg)
|
||||
return
|
||||
|
||||
|
|
@ -489,8 +489,10 @@ class TestCqlshCompletion(CqlshCompletionCase):
|
|||
"b = 'eggs'"),
|
||||
choices=['AND', 'IF', ';'])
|
||||
|
||||
def test_complete_in_batch(self):
|
||||
pass
|
||||
def test_complete_in_begin_batch(self):
|
||||
self.trycompletions('BEGIN ', choices=['BATCH', 'COUNTER', 'UNLOGGED'])
|
||||
self.trycompletions('BEGIN BATCH ', choices=['DELETE', 'INSERT', 'UPDATE', 'USING'])
|
||||
self.trycompletions('BEGIN BATCH INSERT ', immediate='INTO ' )
|
||||
|
||||
def test_complete_in_create_keyspace(self):
|
||||
self.trycompletions('create keyspace ', '', choices=('<identifier>', '<quotedName>', 'IF'))
|
||||
|
|
@ -566,6 +568,23 @@ class TestCqlshCompletion(CqlshCompletionCase):
|
|||
self.trycompletions('DROP KEYSPACE I',
|
||||
immediate='F EXISTS ' + self.cqlsh.keyspace + ' ;')
|
||||
|
||||
def test_complete_in_create_type(self):
|
||||
self.trycompletions('CREATE TYPE foo ', choices=['(', '.'])
|
||||
|
||||
def test_complete_in_drop_type(self):
|
||||
self.trycompletions('DROP TYPE ', choices=['IF', 'system_views.',
|
||||
'tags', 'system_traces.', 'system_distributed.',
|
||||
'phone_number', 'band_info_type', 'address', 'system.', 'system_schema.',
|
||||
'system_auth.', 'system_virtual_schema.', self.cqlsh.keyspace + '.'
|
||||
])
|
||||
|
||||
def test_complete_in_create_trigger(self):
|
||||
self.trycompletions('CREATE TRIGGER ', choices=['<identifier>', '<quotedName>', 'IF' ])
|
||||
self.trycompletions('CREATE TRIGGER foo ', immediate='ON ' )
|
||||
self.trycompletions('CREATE TRIGGER foo ON ', choices=['system.', 'system_auth.',
|
||||
'system_distributed.', 'system_schema.', 'system_traces.', 'system_views.',
|
||||
'system_virtual_schema.' ], other_choices_ok=True)
|
||||
|
||||
def create_columnfamily_table_template(self, name):
|
||||
"""Parameterized test for CREATE COLUMNFAMILY and CREATE TABLE. Since
|
||||
they're synonyms, they should have the same completion behavior, so this
|
||||
|
|
@ -827,24 +846,28 @@ class TestCqlshCompletion(CqlshCompletionCase):
|
|||
'aggmax'],
|
||||
other_choices_ok=True)
|
||||
|
||||
# TODO: CASSANDRA-16640
|
||||
# def test_complete_in_drop_columnfamily(self):
|
||||
# pass
|
||||
#
|
||||
# def test_complete_in_truncate(self):
|
||||
# pass
|
||||
#
|
||||
# def test_complete_in_alter_columnfamily(self):
|
||||
# pass
|
||||
#
|
||||
# def test_complete_in_use(self):
|
||||
# pass
|
||||
#
|
||||
# def test_complete_in_create_index(self):
|
||||
# pass
|
||||
#
|
||||
# def test_complete_in_drop_index(self):
|
||||
# pass
|
||||
def test_complete_in_drop_table(self):
|
||||
self.trycompletions('DROP T', choices=['TABLE', 'TRIGGER', 'TYPE'])
|
||||
self.trycompletions('DROP TA', immediate='BLE ')
|
||||
|
||||
def test_complete_in_truncate(self):
|
||||
self.trycompletions('TR', choices=['TRACING', 'TRUNCATE'])
|
||||
self.trycompletions('TRU', immediate='NCATE ')
|
||||
self.trycompletions('TRUNCATE T', choices=['TABLE', 'twenty_rows_composite_table', 'twenty_rows_table'])
|
||||
|
||||
def test_complete_in_use(self):
|
||||
self.trycompletions('US', immediate='E ')
|
||||
self.trycompletions('USE ', choices=[self.cqlsh.keyspace, 'system', 'system_auth',
|
||||
'system_distributed', 'system_schema', 'system_traces', 'system_views',
|
||||
'system_virtual_schema' ])
|
||||
|
||||
def test_complete_in_create_index(self):
|
||||
self.trycompletions('CREATE I', immediate='NDEX ')
|
||||
self.trycompletions('CREATE INDEX ', choices=['<new_index_name>', 'IF', 'ON'])
|
||||
self.trycompletions('CREATE INDEX example ', immediate='ON ')
|
||||
|
||||
def test_complete_in_drop_index(self):
|
||||
self.trycompletions('DROP I', immediate='NDEX ')
|
||||
|
||||
def test_complete_in_alter_keyspace(self):
|
||||
self.trycompletions('ALTER KEY', 'SPACE ')
|
||||
|
|
@ -955,5 +978,44 @@ class TestCqlshCompletion(CqlshCompletionCase):
|
|||
def test_complete_in_alter_user(self):
|
||||
self.trycompletions('ALTER USER ', choices=['<identifier>', 'IF', '<pgStringLiteral>', '<quotedStringLiteral>'])
|
||||
|
||||
def test_complete_in_create_role(self):
|
||||
self.trycompletions('CREATE ROLE ', choices=['<identifier>', 'IF', '<quotedName>'])
|
||||
self.trycompletions('CREATE ROLE IF ', immediate='NOT EXISTS ');
|
||||
self.trycompletions('CREATE ROLE foo WITH ', choices=['ACCESS', 'HASHED', 'LOGIN', 'OPTIONS', 'PASSWORD', 'SUPERUSER'])
|
||||
self.trycompletions('CREATE ROLE foo WITH HASHED ', immediate='PASSWORD = ');
|
||||
self.trycompletions('CREATE ROLE foo WITH ACCESS TO ', choices=['ALL', 'DATACENTERS'])
|
||||
self.trycompletions('CREATE ROLE foo WITH ACCESS TO ALL ', immediate='DATACENTERS ')
|
||||
|
||||
def test_complete_in_alter_role(self):
|
||||
self.trycompletions('ALTER ROLE ', choices=['<identifier>', 'IF', '<quotedName>'])
|
||||
self.trycompletions('ALTER ROLE foo ', immediate='WITH ')
|
||||
self.trycompletions('ALTER ROLE foo WITH ', choices=['ACCESS', 'HASHED', 'LOGIN', 'OPTIONS', 'PASSWORD', 'SUPERUSER'])
|
||||
self.trycompletions('ALTER ROLE foo WITH ACCESS TO ', choices=['ALL', 'DATACENTERS'])
|
||||
|
||||
def test_complete_in_drop_role(self):
|
||||
self.trycompletions('DROP ROLE ', choices=['<identifier>', 'IF', '<quotedName>'])
|
||||
|
||||
|
||||
def test_complete_in_list(self):
|
||||
self.trycompletions('LIST ', choices=['ALL', 'AUTHORIZE', 'DESCRIBE', 'EXECUTE', 'ROLES', 'USERS', 'ALTER', 'CREATE', 'DROP', 'MODIFY', 'SELECT'])
|
||||
|
||||
|
||||
# Non-CQL Shell Commands
|
||||
|
||||
def test_complete_in_capture(self):
|
||||
self.trycompletions('CAPTURE ', choices=['OFF', ';', '<enter>'], other_choices_ok=True)
|
||||
|
||||
def test_complete_in_paging(self):
|
||||
self.trycompletions('PAGING ', choices=['ON', 'OFF', ';', '<enter>', '<wholenumber>' ] )
|
||||
self.trycompletions('PAGING 50 ', choices=[';', '<enter>' ] )
|
||||
|
||||
def test_complete_in_serial(self):
|
||||
self.trycompletions('SERIAL CONSISTENCY ', choices=[';', '<enter>', 'LOCAL_SERIAL', 'SERIAL'])
|
||||
|
||||
def test_complete_in_show(self):
|
||||
self.trycompletions('SHOW ', choices=['HOST', 'REPLICAS', 'SESSION', 'VERSION'])
|
||||
self.trycompletions('SHOW SESSION ', choices=['<uuid>'])
|
||||
self.trycompletions('SHOW REPLICAS ', choices=['-', '<wholenumber>'])
|
||||
|
||||
def test_complete_in_tracing(self):
|
||||
self.trycompletions('TRACING ', choices=[';', '<enter>', 'OFF', 'ON'])
|
||||
|
|
|
|||
Loading…
Reference in New Issue