kaqing 2.0.50__py3-none-any.whl → 2.0.51__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,11 @@
1
- from adam.commands.cql.cql_table_completer import CqlTableNameCompleter
2
1
  from adam.commands.cql.cql_utils import table_names
3
2
  from adam.repl_state import ReplState
4
3
  from adam.sql.sql_completer import SqlCompleter
5
4
 
6
5
  def cql_completions(state: ReplState) -> dict[str, any]:
7
- table_name_completer = CqlTableNameCompleter(table_names(state))
8
6
  return {
9
7
  'describe': {
10
8
  'keyspaces': None,
11
- 'table': table_name_completer,
9
+ 'table': {t: None for t in table_names(state)},
12
10
  'tables': None},
13
- } | SqlCompleter.completions(table_name_completer)
11
+ } | SqlCompleter.completions(lambda: table_names(state))
@@ -1,16 +1,8 @@
1
- from adam.sql.table_name_completer import NestedDict, TableNameCompleter
1
+ from adam.sql.term_completer import TermCompleter
2
2
 
3
- class CqlTableNameCompleter(TableNameCompleter):
4
- def __init__(self, tables: list[str], nested_dict: NestedDict = {}, ignore_case: bool = True):
5
- self._tables = tables
6
- self.ignore_case = ignore_case
7
- self.append_nested_dict(nested_dict)
3
+ class CqlTableNameCompleter(TermCompleter):
4
+ def __init__(self, tables: list[str], ignore_case: bool = True):
5
+ super().__init__(tables, ignore_case=ignore_case)
8
6
 
9
7
  def __repr__(self) -> str:
10
- return "CqlTableCompleter(%r)" % (len(self._tables))
11
-
12
- def nested(self, data: NestedDict) -> 'TableNameCompleter':
13
- return CqlTableNameCompleter(self._tables).append_nested_dict(data)
14
-
15
- def tables(self) -> list[str]:
16
- return self._tables
8
+ return "CqlTableCompleter(%r)" % (len(self.words))
@@ -1,4 +1,4 @@
1
- from adam.commands.postgres.psql_table_completer import PsqlTableNameCompleter
1
+ from adam.commands.postgres.postgres_utils import pg_table_names
2
2
  from adam.sql.sql_completer import SqlCompleter
3
3
 
4
4
  def psql_completions(ns: str, pg_path: str):
@@ -7,5 +7,4 @@ def psql_completions(ns: str, pg_path: str):
7
7
  '\d': None,
8
8
  '\dt': None,
9
9
  '\du': None
10
- } | SqlCompleter.completions(PsqlTableNameCompleter(ns, pg_path))
11
- # } | PsqlTableCompleter(ns, pg_path).completions()
10
+ } | SqlCompleter.completions(lambda: pg_table_names(ns, pg_path))
@@ -1,18 +1,11 @@
1
1
  from adam.commands.postgres.postgres_utils import pg_table_names
2
- from adam.sql.table_name_completer import NestedDict, TableNameCompleter
2
+ from adam.sql.term_completer import TermCompleter
3
3
 
4
- class PsqlTableNameCompleter(TableNameCompleter):
5
- def __init__(self, namespace: str, pg_path: str, nested_dict: NestedDict = {}, ignore_case: bool = True):
4
+ class PsqlTableNameCompleter(TermCompleter):
5
+ def __init__(self, namespace: str, pg_path: str, ignore_case: bool = True):
6
+ super().__init__(pg_table_names(namespace, pg_path), ignore_case=ignore_case)
6
7
  self.namespace = namespace
7
8
  self.pg_path = pg_path
8
- self.ignore_case = ignore_case
9
- self.append_nested_dict(nested_dict)
10
9
 
11
10
  def __repr__(self) -> str:
12
- return "PsqlTableCompleter(%r, pg_path=%r)" % (self.namespace, self.pg_path)
13
-
14
- def nested(self, data: NestedDict) -> 'TableNameCompleter':
15
- return PsqlTableNameCompleter(self.namespace, self.pg_path).append_nested_dict(data)
16
-
17
- def tables(self) -> list[str]:
18
- return pg_table_names(self.namespace, self.pg_path)
11
+ return "PsqlTableCompleter(%r, pg_path=%r)" % (self.namespace, self.pg_path)
@@ -3,8 +3,8 @@ import functools
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.cql.cql_table_completer import CqlTableNameCompleter
5
5
  from adam.commands.cql.cql_utils import run_cql, table_names, tables
6
- from adam.commands.postgres.psql_table_completer import PsqlTableNameCompleter
7
6
  from adam.commands.postgres.postgres_session import PostgresSession
7
+ from adam.commands.postgres.psql_table_completer import PsqlTableNameCompleter
8
8
  from adam.config import Config
9
9
  from adam.repl_state import ReplState, RequiredState
10
10
  from adam.utils import lines_to_tabular, log, log2
adam/repl.py CHANGED
@@ -18,7 +18,6 @@ from adam.log import Log
18
18
  from adam.repl_commands import ReplCommands
19
19
  from adam.repl_session import ReplSession
20
20
  from adam.repl_state import ReplState
21
- from adam.sql.sql_completer import SqlCompleter
22
21
  from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
23
22
  from adam.apps import Apps
24
23
  from . import __version__
@@ -109,7 +108,7 @@ def enter_repl(state: ReplState):
109
108
  log2(f'Timing auto-completion-calc {cmd.command()}: {time.time() - s1:.2f}')
110
109
 
111
110
  # print(json.dumps(completions, indent=4))
112
- completer = SqlCompleter.from_nested_dict(completions)
111
+ completer = NestedCompleter.from_nested_dict(completions)
113
112
 
114
113
  cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
115
114
  s0 = time.time()
adam/sql/sql_completer.py CHANGED
@@ -1,53 +1,403 @@
1
- from typing import Dict, Iterable, Optional
2
- from prompt_toolkit.completion import CompleteEvent, Completer, Completion, NestedCompleter, WordCompleter
1
+ from typing import Callable, Iterable
2
+ from prompt_toolkit.completion import CompleteEvent, Completer, Completion
3
3
  from prompt_toolkit.document import Document
4
+ import sqlparse
5
+ from sqlparse.sql import Statement, Token
6
+ from sqlparse import tokens as T
4
7
 
5
- from adam.sql.any_completer import AnyCompleter as any
6
- from adam.sql.sql_utils import safe_terms
7
- from adam.sql.table_name_completer import TableNameCompleter
8
+ from adam.sql.term_completer import TermCompleter
8
9
 
9
- class SqlCompleter(NestedCompleter):
10
- def __init__(
11
- self, options: Dict[str, Optional[Completer]], ignore_case: bool = True
12
- ) -> None:
13
- super().__init__(options, ignore_case)
10
+ class SqlCompleter(Completer):
11
+ def __init__(self, tables: Callable[[], list[str]], dml: str = None, debug = False):
12
+ super().__init__()
13
+ self.dml = dml
14
+ self.tables = tables
15
+ self.debug = debug
14
16
 
15
17
  def get_completions(
16
18
  self, document: Document, complete_event: CompleteEvent
17
19
  ) -> Iterable[Completion]:
18
20
  text = document.text_before_cursor.lstrip()
19
- stripped_len = len(document.text_before_cursor) - len(text)
21
+ if self.dml:
22
+ state = f'{self.dml}_'
23
+ text = f'{self.dml} {text}'
20
24
 
21
- terms, has_space = safe_terms(text)
22
- if has_space:
23
- first_term = terms[0]
24
- completer = self.options.get(first_term)
25
+ completer = None
26
+ stmts = sqlparse.parse(text)
27
+ if not stmts:
28
+ completer = TermCompleter(['select', 'insert', 'delete', 'update'])
29
+ else:
30
+ statement: Statement = stmts[0]
31
+ state = self.traverse_tokens(text, statement.tokens)
32
+ if self.debug:
33
+ print('\n =>', state)
34
+ if state == 'dml_incomplete':
35
+ completer = TermCompleter(['select', 'insert', 'delete', 'update'])
25
36
 
26
- if completer is not None:
27
- remaining_text = text[len(first_term) :].lstrip()
28
- move_cursor = len(text) - len(remaining_text) + stripped_len
37
+ elif state == 'select_':
38
+ completer = TermCompleter(['*'])
39
+ elif state == 'select_a':
40
+ completer = TermCompleter(['from'])
41
+ elif state == 'select_a,':
42
+ completer = TermCompleter(['*'])
43
+ elif state == 'select_a_':
44
+ completer = TermCompleter(['from'])
45
+ elif state == "select_a_from_":
46
+ completer = TermCompleter(self.tables())
47
+ elif state == "select_a_from_x_":
48
+ completer = TermCompleter(['where', 'group', 'limit'])
49
+ elif state == "select_a_from_x,":
50
+ completer = TermCompleter(self.tables())
51
+ elif state == "select_a_from_x_where_":
52
+ completer = TermCompleter(['id'])
53
+ elif state == "select_a_from_x_where_id":
54
+ completer = TermCompleter(['=', '<', '<=', '>', '>=', '<>', 'like'])
55
+ elif state == "select_a_from_x_where_id=":
56
+ completer = TermCompleter(["'"])
57
+ elif state == "select_a_from_x_where_id=v_":
58
+ completer = TermCompleter(['and', 'or', 'group', 'limit'])
59
+ elif state == "select_a_from_x_where_id=v_limit_":
60
+ completer = TermCompleter(['1'])
61
+ elif state == "select_a_from_x_group_":
62
+ completer = TermCompleter(['by'])
63
+ elif state == "select_a_from_x_group_by_":
64
+ completer = TermCompleter(['id'])
65
+ elif state == "select_a_from_x_group_by_a,":
66
+ completer = TermCompleter(['id'])
67
+ elif state == "select_a_from_x_group_by_a_":
68
+ completer = TermCompleter(['limit'])
69
+ elif state == "select_a_from_x_group_by_a_limit_":
70
+ completer = TermCompleter(['1'])
29
71
 
30
- new_document = Document(
31
- remaining_text,
32
- cursor_position=document.cursor_position - move_cursor,
33
- )
72
+ elif state == "insert_":
73
+ completer = TermCompleter(['into'])
74
+ elif state == "insert_into_":
75
+ completer = TermCompleter(self.tables())
76
+ elif state == "insert_into_x_":
77
+ completer = TermCompleter(['values'])
78
+ elif state == "insert_into_x(":
79
+ completer = TermCompleter(['id'])
80
+ elif state == "insert_into_x(a,":
81
+ completer = TermCompleter(['id'])
82
+ elif state == "insert_into_x(a)_":
83
+ completer = TermCompleter(['values('])
84
+ elif state == "insert_into_x_values":
85
+ completer = TermCompleter(['('])
86
+ elif state == "insert_into_x_values(":
87
+ completer = TermCompleter(["'"])
34
88
 
35
- for c in completer.get_completions(new_document, complete_event):
36
- yield c
37
- else:
38
- completer = WordCompleter(
39
- list(self.options.keys()), ignore_case=self.ignore_case
40
- )
89
+ elif state == "update_":
90
+ completer = TermCompleter(self.tables())
91
+ elif state == "update_x_":
92
+ completer = TermCompleter(['set'])
93
+ elif state in ["update_x_set_", "update_x_set_a=v,"]:
94
+ completer = TermCompleter(['id'])
95
+ elif state == "update_x_set_a":
96
+ completer = TermCompleter(['='])
97
+ elif state == "update_x_set_a=":
98
+ completer = TermCompleter(["'"])
99
+ elif state == "update_x_set_a=v_":
100
+ completer = TermCompleter(['where'])
101
+ elif state == "update_x_set_a=v_where_":
102
+ completer = TermCompleter(['id'])
103
+ elif state == "update_x_set_a=v_where_id":
104
+ completer = TermCompleter(['='])
105
+ elif state == "update_x_set_a=v_where_id=v_":
106
+ completer = TermCompleter(['and', 'or'])
107
+
108
+ elif state == "delete_":
109
+ completer = TermCompleter(['from'])
110
+ elif state == "delete_from_":
111
+ completer = TermCompleter(self.tables())
112
+ elif state == "delete_from_x_":
113
+ completer = TermCompleter(['where'])
114
+ elif state == "delete_from_x_where_":
115
+ completer = TermCompleter(['id'])
116
+ elif state == "delete_from_x_where_id":
117
+ completer = TermCompleter(['='])
118
+ elif state == "delete_from_x_where_id=":
119
+ completer = TermCompleter(["'"])
120
+ elif state == "delete_from_x_where_id=v_":
121
+ completer = TermCompleter(['and', 'or'])
122
+
123
+ if completer:
41
124
  for c in completer.get_completions(document, complete_event):
42
125
  yield c
43
126
 
44
- def completions(table: TableNameCompleter):
127
+ def traverse_tokens(self, text: str, tokens: list[Token], state: str = None, indent=0):
128
+ # state: str = None
129
+ for token in tokens:
130
+ if self.debug:
131
+ if token.ttype == T.Whitespace:
132
+ print('_ ', end='')
133
+ elif token.ttype in [T.DML, T.Wildcard, T.Punctuation]:
134
+ print(f'{token.value} ', end='')
135
+ elif token.ttype:
136
+ tks = str(token.ttype).split('.')
137
+ typ = tks[len(tks) - 1]
138
+ if ' ' in token.value:
139
+ print(f'"{token.value}:{typ}" ', end='')
140
+ else:
141
+ print(f'{token.value}:{typ} ', end='')
142
+ # print(" " * indent + f"Token: {token.value}, Type: {token.ttype}@{token.ttype.__class__}")
143
+ node: str = None
144
+ if token.is_group:
145
+ state = self.traverse_tokens(text, token.tokens, state, indent + 1)
146
+ else:
147
+ if not state:
148
+ if token.ttype == T.Keyword.DML and token.value.lower() == 'select':
149
+ state = 'select'
150
+ if token.ttype == T.Keyword.DML and token.value.lower() == 'insert':
151
+ state = 'insert'
152
+ if token.ttype == T.Keyword.DML and token.value.lower() == 'update':
153
+ state = 'update'
154
+ if token.ttype == T.Keyword.DML and token.value.lower() == 'delete':
155
+ state = 'delete'
156
+ elif token.ttype == T.Name:
157
+ state = 'dml_incomplete'
158
+
159
+ elif state == 'select':
160
+ if token.ttype == T.Text.Whitespace:
161
+ state = 'select_'
162
+ elif state == 'select_':
163
+ if token.ttype == T.Name or token.ttype == T.Wildcard:
164
+ state = 'select_a'
165
+ elif state == 'select_a':
166
+ if token.ttype == T.Text.Whitespace:
167
+ state = 'select_a_'
168
+ elif token.ttype == T.Punctuation and token.value == ',':
169
+ state = 'select_a,'
170
+ elif state == 'select_a,':
171
+ if token.ttype == T.Name or token.ttype == T.Wildcard:
172
+ state = 'select_a'
173
+ elif state == 'select_a_':
174
+ if token.ttype == T.Keyword and token.value.lower() == 'from':
175
+ state = 'select_a_from'
176
+ elif state == 'select_a_from':
177
+ if token.ttype == T.Text.Whitespace:
178
+ state = 'select_a_from_'
179
+ elif state == 'select_a_from_':
180
+ if token.ttype == T.Name:
181
+ state = 'select_a_from_x'
182
+ elif state == 'select_a_from_x':
183
+ if token.ttype == T.Text.Whitespace:
184
+ state = 'select_a_from_x_'
185
+ elif token.ttype == T.Punctuation and token.value == ',':
186
+ state = 'select_a_from_x,'
187
+ elif state == 'select_a_from_x,':
188
+ if token.ttype == T.Name:
189
+ state = 'select_a_from_x'
190
+ elif state == 'select_a_from_x_':
191
+ if token.ttype == T.Keyword and token.value.lower() == 'where':
192
+ state = 'select_a_from_x_where'
193
+ elif token.ttype == T.Keyword and token.value.lower() == 'limit':
194
+ state = 'select_a_from_x_where_id=v_limit'
195
+ elif token.ttype == T.Keyword and token.value.lower() == 'group':
196
+ state = 'select_a_from_x_group'
197
+ elif token.ttype == T.Keyword and token.value.lower() == 'group by':
198
+ state = 'select_a_from_x_group_by'
199
+ elif state == 'select_a_from_x_where':
200
+ if token.ttype == T.Text.Whitespace:
201
+ state = 'select_a_from_x_where_'
202
+ elif state == 'select_a_from_x_where_':
203
+ if token.ttype == T.Name:
204
+ state = 'select_a_from_x_where_id'
205
+ elif state == 'select_a_from_x_where_id':
206
+ if token.ttype == T.Operator.Comparison:
207
+ state = 'select_a_from_x_where_id='
208
+ elif state == 'select_a_from_x_where_id=':
209
+ if token.ttype in [T.Literal.String.Single, T.Name]:
210
+ state = 'select_a_from_x_where_id=v'
211
+ elif state == 'select_a_from_x_where_id=v':
212
+ if token.ttype == T.Text.Whitespace:
213
+ state = 'select_a_from_x_where_id=v_'
214
+ elif state == 'select_a_from_x_where_id=v_':
215
+ if token.ttype == T.Keyword and token.value.lower() in ['and', 'or']:
216
+ state = 'select_a_from_x_where'
217
+ elif token.ttype == T.Keyword and token.value.lower() == 'group':
218
+ state = 'select_a_from_x_group'
219
+ elif token.ttype == T.Keyword and token.value.lower() == 'limit':
220
+ state = 'select_a_from_x_where_id=v_limit'
221
+ elif state == 'select_a_from_x_group':
222
+ if token.ttype == T.Text.Whitespace:
223
+ state = 'select_a_from_x_group_'
224
+ elif state == 'select_a_from_x_group_':
225
+ if token.ttype == T.Keyword and token.value.lower() == 'by':
226
+ state = 'select_a_from_x_group_by'
227
+ elif state == 'select_a_from_x_group_by':
228
+ if token.ttype == T.Text.Whitespace:
229
+ state = 'select_a_from_x_group_by_'
230
+ elif state == 'select_a_from_x_group_by_':
231
+ if token.ttype == T.Name:
232
+ state = 'select_a_from_x_group_by_a'
233
+ elif state == 'select_a_from_x_group_by_a':
234
+ if token.ttype == T.Text.Whitespace:
235
+ state = 'select_a_from_x_group_by_a_'
236
+ elif token.ttype == T.Punctuation and token.value == ',':
237
+ state = 'select_a_from_x_group_by_a,'
238
+ elif state == 'select_a_from_x_group_by_a,':
239
+ if token.ttype == T.Name:
240
+ state = 'select_a_from_x_group_by_a'
241
+ elif state == 'select_a_from_x_group_by_a_':
242
+ if token.ttype == T.Keyword and token.value.lower() == 'limit':
243
+ state = 'select_a_from_x_where_id=v_limit'
244
+ elif state == 'select_a_from_x_where_id=v_limit':
245
+ if token.ttype == T.Text.Whitespace:
246
+ state = 'select_a_from_x_where_id=v_limit_'
247
+
248
+ elif state == 'insert':
249
+ if token.ttype == T.Text.Whitespace:
250
+ state = 'insert_'
251
+ elif state == 'insert_':
252
+ if token.ttype == T.Keyword and token.value.lower() == 'into':
253
+ state = 'insert_into'
254
+ elif state == 'insert_into':
255
+ if token.ttype == T.Text.Whitespace:
256
+ state = 'insert_into_'
257
+ elif state == 'insert_into_':
258
+ if token.ttype == T.Name:
259
+ state = 'insert_into_x'
260
+ elif state == 'insert_into_x':
261
+ if token.ttype == T.Text.Whitespace:
262
+ state = 'insert_into_x_'
263
+ elif token.ttype == T.Punctuation and token.value == '(':
264
+ state = 'insert_into_x('
265
+ elif state == 'insert_into_x_':
266
+ if token.ttype == T.Punctuation and token.value == '(':
267
+ state = 'insert_into_x('
268
+ elif token.ttype == T.Keyword and token.value.lower() == 'values':
269
+ state = 'insert_into_x_values'
270
+ elif state == 'insert_into_x(':
271
+ if token.ttype == T.Name:
272
+ state = 'insert_into_x(a'
273
+ elif state == 'insert_into_x(a':
274
+ if token.ttype == T.Punctuation and token.value == ',':
275
+ state = 'insert_into_x(a,'
276
+ elif token.ttype == T.Punctuation and token.value == ')':
277
+ state = 'insert_into_x(a)'
278
+ elif state == 'insert_into_x(a,':
279
+ if token.ttype == T.Name:
280
+ state = 'insert_into_x(a'
281
+ elif state == 'insert_into_x(a)':
282
+ if token.ttype == T.Text.Whitespace:
283
+ state = 'insert_into_x(a)_'
284
+ elif state == 'insert_into_x(a)_':
285
+ if token.ttype == T.Keyword and token.value.lower() == 'values':
286
+ state = 'insert_into_x_values'
287
+ elif state == 'insert_into_x_values':
288
+ if token.ttype == T.Punctuation and token.value == '(':
289
+ state = 'insert_into_x_values('
290
+ elif state == 'insert_into_x_values(':
291
+ if token.ttype in [T.Literal.String.Single, T.Name]:
292
+ state = 'insert_into_x_values(v'
293
+ elif state == 'insert_into_x_values(v':
294
+ if token.ttype == T.Punctuation and token.value == ',':
295
+ state = 'insert_into_x_values(v,'
296
+ elif token.ttype == T.Punctuation and token.value == ')':
297
+ state = 'insert_into_x_values(v)'
298
+ elif state == 'insert_into_x_values(v,':
299
+ if token.ttype in [T.Literal.String.Single, T.Name]:
300
+ state = 'insert_into_x_values(v'
301
+
302
+ elif state == 'update':
303
+ if token.ttype == T.Text.Whitespace:
304
+ state = 'update_'
305
+ elif state == 'update_':
306
+ if token.ttype == T.Name:
307
+ state = 'update_x'
308
+ elif state == 'update_x':
309
+ if token.ttype == T.Text.Whitespace:
310
+ state = 'update_x_'
311
+ elif state == 'update_x_':
312
+ if token.ttype == T.Keyword and token.value.lower() == 'set':
313
+ state = 'update_x_set'
314
+ elif state == 'update_x_set':
315
+ if token.ttype == T.Text.Whitespace:
316
+ state = 'update_x_set_'
317
+ elif state == 'update_x_set_':
318
+ if token.ttype == T.Name:
319
+ state = 'update_x_set_a'
320
+ elif state == 'update_x_set_a':
321
+ if token.ttype == T.Operator.Comparison:
322
+ state = 'update_x_set_a='
323
+ elif state == 'update_x_set_a=':
324
+ if token.ttype in [T.Literal.String.Single, T.Name]:
325
+ state = 'update_x_set_a=v'
326
+ elif state == 'update_x_set_a=v':
327
+ if token.ttype == T.Punctuation and token.value == ',':
328
+ state = 'update_x_set_a=v,'
329
+ elif token.ttype == T.Text.Whitespace:
330
+ state = 'update_x_set_a=v_'
331
+ elif state == 'update_x_set_a=v,':
332
+ if token.ttype == T.Name:
333
+ state = 'update_x_set_a'
334
+ elif state == 'update_x_set_a=v_':
335
+ if token.ttype == T.Punctuation and token.value == ',':
336
+ state = 'update_x_set_a=v,'
337
+ elif token.ttype == T.Keyword and token.value.lower() == 'where':
338
+ state = 'update_x_set_a=v_where'
339
+ elif state == 'update_x_set_a=v_where':
340
+ if token.ttype == T.Text.Whitespace:
341
+ state = 'update_x_set_a=v_where_'
342
+ elif state == 'update_x_set_a=v_where_':
343
+ if token.ttype == T.Name:
344
+ state = 'update_x_set_a=v_where_id'
345
+ elif state == 'update_x_set_a=v_where_id':
346
+ if token.ttype == T.Operator.Comparison:
347
+ state = 'update_x_set_a=v_where_id='
348
+ elif state == 'update_x_set_a=v_where_id=':
349
+ if token.ttype in [T.Literal.String.Single, T.Name]:
350
+ state = 'update_x_set_a=v_where_id=v'
351
+ elif state == 'update_x_set_a=v_where_id=v':
352
+ if token.ttype == T.Text.Whitespace:
353
+ state = 'update_x_set_a=v_where_id=v_'
354
+ elif state == 'update_x_set_a=v_where_id=v_':
355
+ if token.ttype == T.Keyword and token.value.lower() in ['and', 'or']:
356
+ state = 'update_x_set_a=v_where'
357
+
358
+ elif state == 'delete':
359
+ if token.ttype == T.Text.Whitespace:
360
+ state = 'delete_'
361
+ elif state == 'delete_':
362
+ if token.ttype == T.Keyword and token.value.lower() == 'from':
363
+ state = 'delete_from'
364
+ elif state == 'delete_from':
365
+ if token.ttype == T.Text.Whitespace:
366
+ state = 'delete_from_'
367
+ elif state == 'delete_from_':
368
+ if token.ttype == T.Name:
369
+ state = 'delete_from_x'
370
+ elif state == 'delete_from_x':
371
+ if token.ttype == T.Text.Whitespace:
372
+ state = 'delete_from_x_'
373
+ elif state == 'delete_from_x_':
374
+ if token.ttype == T.Keyword and token.value.lower() == 'where':
375
+ state = 'delete_from_x_where'
376
+ elif state == 'delete_from_x_where':
377
+ if token.ttype == T.Text.Whitespace:
378
+ state = 'delete_from_x_where_'
379
+ elif state == 'delete_from_x_where_':
380
+ if token.ttype == T.Name:
381
+ state = 'delete_from_x_where_id'
382
+ elif state == 'delete_from_x_where_id':
383
+ if token.ttype == T.Operator.Comparison:
384
+ state = 'delete_from_x_where_id='
385
+ elif state == 'delete_from_x_where_id=':
386
+ if token.ttype in [T.Literal.String.Single, T.Name]:
387
+ state = 'delete_from_x_where_id=v'
388
+ elif state == 'delete_from_x_where_id=v':
389
+ if token.ttype == T.Text.Whitespace:
390
+ state = 'delete_from_x_where_id=v_'
391
+ elif state == 'delete_from_x_where_id=v_':
392
+ if token.ttype == T.Keyword and token.value.lower() in ['and', 'or']:
393
+ state = 'delete_from_x_where'
394
+
395
+ return state
396
+
397
+ def completions(table_names: Callable[[], list[str]]):
45
398
  return {
46
- 'delete': {'from': table.nested({'where': any('id').nested({'=': any("'id'")})})},
47
- 'insert': {'into': table.nested({'values(': None})},
48
- 'select': any('*').nested({'from': table.nested({
49
- 'limit': any('1'),
50
- 'where': any('id').nested({'=': any("'id'").nested({'limit': any('1')})})
51
- })}),
52
- 'update': table.nested({'set': {'column': {'=': None}}}),
399
+ 'delete': SqlCompleter(table_names, 'delete'),
400
+ 'insert': SqlCompleter(table_names, 'insert'),
401
+ 'select': SqlCompleter(table_names, 'select'),
402
+ 'update': SqlCompleter(table_names, 'update'),
53
403
  }
@@ -0,0 +1,66 @@
1
+ from typing import Callable, Iterable, List, Mapping, Optional, Pattern, Union
2
+
3
+ from prompt_toolkit.completion import CompleteEvent, Completer, Completion, WordCompleter
4
+ from prompt_toolkit.document import Document
5
+ from prompt_toolkit.formatted_text import AnyFormattedText
6
+
7
+ __all__ = [
8
+ "TermCompleter",
9
+ ]
10
+
11
+ class TermCompleter(WordCompleter):
12
+ def __init__(
13
+ self,
14
+ words: Union[List[str], Callable[[], List[str]]],
15
+ ignore_case: bool = False,
16
+ display_dict: Optional[Mapping[str, AnyFormattedText]] = None,
17
+ meta_dict: Optional[Mapping[str, AnyFormattedText]] = None,
18
+ WORD: bool = False,
19
+ sentence: bool = False,
20
+ match_middle: bool = False,
21
+ pattern: Optional[Pattern[str]] = None,
22
+ ) -> None:
23
+ super().__init__(words, ignore_case, display_dict, meta_dict, WORD, sentence, match_middle, pattern)
24
+
25
+ def get_completions(
26
+ self, document: Document, complete_event: CompleteEvent
27
+ ) -> Iterable[Completion]:
28
+ # Get list of words.
29
+ words = self.words
30
+ if callable(words):
31
+ words = words()
32
+
33
+ # Get word/text before cursor.
34
+ if self.sentence:
35
+ word_before_cursor = document.text_before_cursor
36
+ else:
37
+ word_before_cursor = document.get_word_before_cursor(
38
+ WORD=self.WORD, pattern=self.pattern
39
+ )
40
+
41
+ if self.ignore_case:
42
+ word_before_cursor = word_before_cursor.lower()
43
+
44
+ def word_matches(word: str) -> bool:
45
+ """True when the word before the cursor matches."""
46
+ if self.ignore_case:
47
+ word = word.lower()
48
+
49
+ if word_before_cursor in ['(', ',', '=']:
50
+ return True
51
+
52
+ if self.match_middle:
53
+ return word_before_cursor in word
54
+ else:
55
+ return word.startswith(word_before_cursor)
56
+
57
+ for a in words:
58
+ if word_matches(a):
59
+ display = self.display_dict.get(a, a)
60
+ display_meta = self.meta_dict.get(a, "")
61
+ yield Completion(
62
+ a,
63
+ -len(word_before_cursor),
64
+ display=display,
65
+ display_meta=display_meta,
66
+ )
adam/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- __version__ = "2.0.50" #: the working version
4
+ __version__ = "2.0.51" #: the working version
5
5
  __release__ = "1.0.0" #: the release version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.50
3
+ Version: 2.0.51
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -9,12 +9,12 @@ adam/embedded_apps.py,sha256=lKPx63mKzJbNmwz0rgL4gF76M9fDGxraYTtNAIGnZ_s,419
9
9
  adam/embedded_params.py,sha256=_9tBKpkSzBfzm-s3tUgZs8DcSVBnPA1iumG0ZRCbZIs,4586
10
10
  adam/log.py,sha256=gg5DK52wLPc9cjykeh0WFHyAk1qI3HEpGaAK8W2dzXY,1146
11
11
  adam/pod_exec_result.py,sha256=nq0xnCNOpUGBSijGF0H-YNrwBc9vUQs4DkvLMIFS5LQ,951
12
- adam/repl.py,sha256=ACIBgqitFt5z6lKFSeF4JOXbnCa3seZHWxFiMJ5Q9zw,7373
12
+ adam/repl.py,sha256=X9ga1iZFIXADQxBXvztFyVNBrfBRxiFLxTUYkm11img,7328
13
13
  adam/repl_commands.py,sha256=WA90Rl27Juctzr3U3kfCDk5N-oYMKlfWbZeafUgk7k0,4723
14
14
  adam/repl_session.py,sha256=uIogcvWBh7wd8QQ-p_JgLsyJ8YJgINw5vOd6JIsd7Vo,472
15
15
  adam/repl_state.py,sha256=591d7gV6uQSFtm7IWdlIYAHjfAzs9bdvIkwlIAeKddE,7540
16
16
  adam/utils.py,sha256=2DoWsrcaioFFH0-RjT30qelVRPUJqCGTfz_ucfE7F8g,7406
17
- adam/version.py,sha256=LFuTm_lavjxHMfAJnqFwLX9zL3RVjQ6n-Au9M0IztXo,139
17
+ adam/version.py,sha256=DIVzASNDynfH_uX-JULcKL8jQRSiIpR4Iw9R6p2ZFXM,139
18
18
  adam/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  adam/checks/check.py,sha256=Qopr3huYcMu2bzQgb99dEUYjFzkjKHRI76S6KA9b9Rk,702
20
20
  adam/checks/check_context.py,sha256=FEHkQ32jY1EDopQ2uYWqy9v7aEEX1orLpJWhopwAlh4,402
@@ -69,7 +69,7 @@ adam/commands/nodetool.py,sha256=HV9yDzMhRjS4lw6UfV7Hc1pcmeSx5a1jU6cAEKSZ1Bg,233
69
69
  adam/commands/nodetool_commands.py,sha256=5IgWC3rmeDD1cgwqQjiiWzi-wJpJ3n_8pAzz_9phXuk,2635
70
70
  adam/commands/param_get.py,sha256=kPAAppK2T0tEFRnSIVFLDPIIGHhgLA7drJhn8TRyvvE,1305
71
71
  adam/commands/param_set.py,sha256=QDIuqfU80aWCB16OK49yf7XRaRTWwiLkwMsJuVikq9I,1271
72
- adam/commands/preview_table.py,sha256=EJZms-8sXqwDDNjix92z2tpU9823-WKv6y-Z3A7ucao,3068
72
+ adam/commands/preview_table.py,sha256=5im47Uk6RclgkZD-Ci0lBs1eosnfvBtKt2lgsb_bohs,3068
73
73
  adam/commands/pwd.py,sha256=VlgFjxFl66I7Df1YI6cuiEeY6Q13lEavMKfrzHLESKo,2340
74
74
  adam/commands/report.py,sha256=Ky45LIzSlB_X4V12JZWjU3SA2u4_FKRencRTq7psOWU,1944
75
75
  adam/commands/restart.py,sha256=Hik1t5rjH2ATZv4tzwrGB3e44b3dNuATgY327_Nb8Bs,2044
@@ -77,8 +77,8 @@ adam/commands/rollout.py,sha256=52_4ijna3v-8Oug12et43DRHFDNhiN34p6xLTQmhdbQ,2959
77
77
  adam/commands/shell.py,sha256=wY_PIx7Lt6vuxhFArlfxdEnBbrouCJ3yNHhFn17DEqw,848
78
78
  adam/commands/watch.py,sha256=mmBFpB8T1V7zrNs5b2YNyDDztMym_ILPDdkrbdAXTas,2438
79
79
  adam/commands/cql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
- adam/commands/cql/cql_completions.py,sha256=BfaBlLMBdSSbuYmuyVMhOcJ7IgELvYKJroq4qOjoZWc,529
81
- adam/commands/cql/cql_table_completer.py,sha256=ktTXC_Ii8NhxRbvUebc_Rg__Z7v2faQJBt3mR-5LPoI,633
80
+ adam/commands/cql/cql_completions.py,sha256=dXe51NTWEJis76587IWSn9Av-cjC0J6KMaxlBKfF4wM,411
81
+ adam/commands/cql/cql_table_completer.py,sha256=Tth6lmZ1eCEbJeAVZojTx594ttQeeVf-OjhhkSLyRnI,312
82
82
  adam/commands/cql/cql_utils.py,sha256=q5hzAUVh7h8iVVH2s0M4E76zWqaMUDXULMn412mfHII,3893
83
83
  adam/commands/cql/cqlsh.py,sha256=qEQufaDVi9FXkvruum6OHQDfLX01DVWVDnWsAjyCZYQ,2661
84
84
  adam/commands/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -112,8 +112,8 @@ adam/commands/postgres/postgres_ls.py,sha256=HwZTgwGKXUqHX33S8aQPF6FqCrLqtoz4cLy
112
112
  adam/commands/postgres/postgres_preview.py,sha256=MLzdEc4mvNj6V1Q8jO5OPznXyYELJHgd35_eQgLlNIU,1274
113
113
  adam/commands/postgres/postgres_session.py,sha256=RcqkCgtA78M-9LKTwG6pp8n9JwjmURXgf1FknIIPl9g,9305
114
114
  adam/commands/postgres/postgres_utils.py,sha256=mC5PZXrfxzqZt6n_HYASwe6Y-OyAK3QwEtDeVb_TKrA,877
115
- adam/commands/postgres/psql_completions.py,sha256=huEvqYTjBk_3CY_Tu1dDeUlaNwPIMLagnv9QuSWCB5U,392
116
- adam/commands/postgres/psql_table_completer.py,sha256=8-4flf-PEtQGOSjTdA_93ht1EoZGZ4-dAbrXtyVblS4,819
115
+ adam/commands/postgres/psql_completions.py,sha256=IHcSy-fh028_rYw2gcXaPuf_4TidP5a2hPrl63N643M,322
116
+ adam/commands/postgres/psql_table_completer.py,sha256=WI9VvnI2w6U8HZOdPPiacpf4ShPjHuunHnOtrx7LYG8,509
117
117
  adam/commands/reaper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
118
  adam/commands/reaper/reaper.py,sha256=83R0ZRitEwaYKKssfKxn3zAzLnWIP9QKd1mA6awceS8,1908
119
119
  adam/commands/reaper/reaper_forward.py,sha256=mUp409MzT91cVXGxoPfBGceaR3qZ0rVdWKGdyzPNzSA,3177
@@ -164,10 +164,9 @@ adam/k8s_utils/services.py,sha256=EOJJGACVbbRvu5T3rMKqIJqgYic1_MSJ17EA0TJ6UOk,31
164
164
  adam/k8s_utils/statefulsets.py,sha256=hiBOmJZ3KTI6_naAFzNoW1NoYnnBG35BZ7RMdPhNC6o,4664
165
165
  adam/k8s_utils/volumes.py,sha256=RIBmlOSWM3V3QVXLCFT0owVOyh4rGG1ETp521a-6ndo,1137
166
166
  adam/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
- adam/sql/any_completer.py,sha256=hPnhqAyWIk1-gyZsna1X7AJ8po23cYR-MvYY-7iBn3w,3184
168
- adam/sql/sql_completer.py,sha256=9JSZj-Rv5aag720xuQLgq9WlseLtPEAcQXx6OH-pFP8,2160
167
+ adam/sql/sql_completer.py,sha256=RhfE8_ecn84HtiCFPMDvKrkPySFXVIJ2ez9bN8-wdP4,20902
169
168
  adam/sql/sql_utils.py,sha256=MLoxB9h22WZiANu0SZzmBJcY2gtb6f_D4jnoJEjLgPc,171
170
- adam/sql/table_name_completer.py,sha256=n_vJbsfM4XYN0tCjov1l-4skFYO3xaLcyOVcZ77mteo,519
169
+ adam/sql/term_completer.py,sha256=O-sUxFVc1DJmPQCdT-XPK2SSkUe4AL1dw8ZPXXicATY,2273
171
170
  adam/sso/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
171
  adam/sso/authenticator.py,sha256=BCm16L9zf5aLU47-sTCnudn2zLPwd8M2wwRminJfsqw,615
173
172
  adam/sso/authn_ad.py,sha256=fDW8UR3WWykny5Awa5dQjjBUSFzIDz4aMn-lwXoABl8,5857
@@ -178,8 +177,8 @@ adam/sso/idp.py,sha256=fvcwUw_URTgsO6ySaqTIw0zQT2qRO1IPSGhf6rPtybo,5804
178
177
  adam/sso/idp_login.py,sha256=QAtCUeDTVWliJy40RK_oac8Vgybr13xH8wzeBoxPaa8,1754
179
178
  adam/sso/idp_session.py,sha256=9BUHNRf70u4rVKrVY1HKPOEmOviXvkjam8WJxmXSKIM,1735
180
179
  adam/sso/sso_config.py,sha256=5N8WZgIJQBtHUy585XLRWKjpU87_v6QluyNK9E27D5s,2459
181
- kaqing-2.0.50.dist-info/METADATA,sha256=6cRmIvrJppOAGCWN23OkycCXqvwVuUh8CMOcImdjjxs,132
182
- kaqing-2.0.50.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
183
- kaqing-2.0.50.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
184
- kaqing-2.0.50.dist-info/top_level.txt,sha256=8_2PZkwBb-xDcnc8a2rAbQeJhXKXskc7zTP7pSPa1fw,5
185
- kaqing-2.0.50.dist-info/RECORD,,
180
+ kaqing-2.0.51.dist-info/METADATA,sha256=yrXdUA18-Fl_t3WHsjhq9WePo338WX7YSh0VD0M6fgM,132
181
+ kaqing-2.0.51.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
182
+ kaqing-2.0.51.dist-info/entry_points.txt,sha256=SkzhuQJUWsXOzHeZ5TgQ2c3_g53UGK23zzJU_JTZOZI,39
183
+ kaqing-2.0.51.dist-info/top_level.txt,sha256=8_2PZkwBb-xDcnc8a2rAbQeJhXKXskc7zTP7pSPa1fw,5
184
+ kaqing-2.0.51.dist-info/RECORD,,
adam/sql/any_completer.py DELETED
@@ -1,84 +0,0 @@
1
- from typing import Any, Dict, Iterable, Mapping, Optional, Set, Union
2
- from prompt_toolkit.completion import CompleteEvent, Completer, Completion, NestedCompleter, WordCompleter
3
- from prompt_toolkit.document import Document
4
-
5
- from adam.sql.sql_utils import safe_terms
6
-
7
- NestedDict = Mapping[str, Union[Any, Set[str], None, Completer]]
8
-
9
- class AnyCompleter(Completer):
10
- def __init__(self, default: str = None, nested_dict: NestedDict = {}, ignore_case: bool = True):
11
- self.default = default
12
- self.ignore_case = ignore_case
13
- self.append_nested_dict(nested_dict)
14
-
15
- def append_nested_dict(self, data: NestedDict) -> "AnyCompleter":
16
- options: Dict[str, Optional[Completer]] = {}
17
- for key, value in data.items():
18
- if isinstance(value, Completer):
19
- options[key] = value
20
- elif isinstance(value, dict):
21
- options[key] = NestedCompleter.from_nested_dict(value)
22
- elif isinstance(value, set):
23
- options[key] = NestedCompleter.from_nested_dict({item: None for item in value})
24
- else:
25
- assert value is None
26
- options[key] = None
27
-
28
- self.options = options
29
-
30
- return self
31
-
32
- def get_completions(
33
- self, document: Document, complete_event: CompleteEvent
34
- ) -> Iterable[Completion]:
35
- text = document.text_before_cursor.lstrip()
36
- stripped_len = len(document.text_before_cursor) - len(text)
37
-
38
- terms, has_space = safe_terms(text)
39
- if has_space:
40
- second_term = None
41
- if len(terms) > 1:
42
- second_term = terms[1]
43
-
44
- yielded = False
45
- if second_term:
46
- completer = self.options.get(second_term)
47
-
48
- if completer is not None:
49
- first_term = terms[0]
50
- remaining_text = text[len(first_term) :].lstrip()
51
- move_cursor = len(text) - len(remaining_text) + stripped_len
52
-
53
- remaining_text = remaining_text[len(second_term) :].lstrip()
54
- move_cursor = len(text) - len(remaining_text) + stripped_len
55
-
56
- new_document = Document(
57
- remaining_text,
58
- cursor_position=document.cursor_position - move_cursor,
59
- )
60
-
61
- for c in completer.get_completions(new_document, complete_event):
62
- yield c
63
- yielded = True
64
-
65
- if not yielded:
66
- completer = WordCompleter(
67
- list(self.options.keys()), ignore_case=self.ignore_case
68
- )
69
- for c in completer.get_completions(document, complete_event):
70
- yield c
71
- elif words := self.words():
72
- for c in words.get_completions(document, complete_event):
73
- yield c
74
-
75
- def words(self):
76
- if not self.default:
77
- return None
78
-
79
- return WordCompleter(
80
- [self.default], ignore_case=self.ignore_case
81
- )
82
-
83
- def nested(self, data: NestedDict) -> 'AnyCompleter':
84
- return AnyCompleter(self.default).append_nested_dict(data)
@@ -1,17 +0,0 @@
1
- from abc import abstractmethod
2
- from prompt_toolkit.completion import WordCompleter
3
-
4
- from .any_completer import AnyCompleter, NestedDict
5
-
6
- class TableNameCompleter(AnyCompleter):
7
- def __init__(self, nested_dict: NestedDict = {}, ignore_case: bool = True):
8
- super().__init__(nested_dict=nested_dict, ignore_case=ignore_case)
9
-
10
- def words(self):
11
- return WordCompleter(
12
- self.tables(), ignore_case=self.ignore_case
13
- )
14
-
15
- @abstractmethod
16
- def tables(self) -> list[str]:
17
- pass