kaqing 2.0.184__py3-none-any.whl → 2.0.214__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.

Potentially problematic release.


This version of kaqing might be problematic. Click here for more details.

Files changed (152) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +15 -15
  3. adam/commands/app/app.py +2 -2
  4. adam/commands/app/show_app_actions.py +1 -1
  5. adam/commands/{show → app}/show_login.py +1 -1
  6. adam/commands/app/utils_app.py +9 -1
  7. adam/commands/audit/audit.py +6 -20
  8. adam/commands/audit/audit_repair_tables.py +1 -1
  9. adam/commands/audit/audit_run.py +1 -1
  10. adam/commands/audit/completions_l.py +15 -0
  11. adam/commands/audit/show_last10.py +0 -1
  12. adam/commands/bash/bash.py +1 -1
  13. adam/commands/bash/utils_bash.py +1 -1
  14. adam/commands/cassandra/download_cassandra_log.py +45 -0
  15. adam/commands/cassandra/restart_cluster.py +47 -0
  16. adam/commands/cassandra/restart_node.py +51 -0
  17. adam/commands/cassandra/restart_nodes.py +47 -0
  18. adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
  19. adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
  20. adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
  21. adam/commands/cassandra/show_processes.py +50 -0
  22. adam/commands/{show → cassandra}/show_storage.py +10 -8
  23. adam/commands/cli/__init__.py +0 -0
  24. adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
  25. adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
  26. adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
  27. adam/commands/command.py +22 -9
  28. adam/commands/commands_utils.py +14 -6
  29. adam/commands/config/__init__.py +0 -0
  30. adam/commands/{show → config}/show_params.py +1 -1
  31. adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
  32. adam/commands/cql/completions_c.py +29 -0
  33. adam/commands/cql/cqlsh.py +2 -6
  34. adam/commands/cql/utils_cql.py +26 -17
  35. adam/commands/debug/__init__.py +0 -0
  36. adam/commands/debug/debug.py +22 -0
  37. adam/commands/debug/debug_completes.py +35 -0
  38. adam/commands/debug/debug_timings.py +35 -0
  39. adam/commands/debug/show_offloaded_completes.py +45 -0
  40. adam/commands/devices/device.py +30 -4
  41. adam/commands/devices/device_app.py +1 -1
  42. adam/commands/devices/device_export.py +5 -2
  43. adam/commands/devices/device_postgres.py +13 -3
  44. adam/commands/devices/devices.py +1 -1
  45. adam/commands/diag/__init__.py +0 -0
  46. adam/commands/{check.py → diag/check.py} +1 -1
  47. adam/commands/diag/generate_report.py +52 -0
  48. adam/commands/export/completions_x.py +11 -0
  49. adam/commands/export/download_export_session.py +2 -1
  50. adam/commands/export/export.py +0 -16
  51. adam/commands/export/export_databases.py +16 -10
  52. adam/commands/export/export_select.py +8 -33
  53. adam/commands/export/export_sessions.py +12 -11
  54. adam/commands/export/export_use.py +3 -3
  55. adam/commands/export/export_x_select.py +48 -0
  56. adam/commands/export/exporter.py +140 -53
  57. adam/commands/export/import_files.py +2 -2
  58. adam/commands/export/import_session.py +0 -4
  59. adam/commands/export/importer.py +11 -11
  60. adam/commands/export/importer_athena.py +15 -35
  61. adam/commands/export/importer_sqlite.py +19 -8
  62. adam/commands/export/show_column_counts.py +10 -10
  63. adam/commands/export/show_export_databases.py +2 -1
  64. adam/commands/export/show_export_session.py +1 -1
  65. adam/commands/export/show_export_sessions.py +1 -1
  66. adam/commands/export/utils_export.py +38 -15
  67. adam/commands/fs/__init__.py +0 -0
  68. adam/commands/{cat.py → fs/cat.py} +2 -2
  69. adam/commands/fs/cat_local.py +42 -0
  70. adam/commands/{cd.py → fs/cd.py} +2 -2
  71. adam/commands/{download_file.py → fs/download_file.py} +5 -5
  72. adam/commands/{find_files.py → fs/find_files.py} +4 -4
  73. adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
  74. adam/commands/{head.py → fs/head.py} +2 -2
  75. adam/commands/{ls.py → fs/ls.py} +2 -2
  76. adam/commands/fs/ls_local.py +40 -0
  77. adam/commands/fs/rm.py +18 -0
  78. adam/commands/fs/rm_downloads.py +39 -0
  79. adam/commands/fs/rm_logs.py +38 -0
  80. adam/commands/{show → fs}/show_adam.py +1 -1
  81. adam/commands/intermediate_command.py +3 -0
  82. adam/commands/medusa/medusa_restore.py +2 -16
  83. adam/commands/medusa/utils_medusa.py +15 -0
  84. adam/commands/nodetool/__init__.py +0 -0
  85. adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
  86. adam/commands/postgres/completions_p.py +22 -0
  87. adam/commands/postgres/postgres.py +7 -14
  88. adam/commands/postgres/postgres_databases.py +3 -3
  89. adam/commands/postgres/postgres_ls.py +1 -1
  90. adam/commands/postgres/utils_postgres.py +12 -2
  91. adam/commands/preview_table.py +1 -1
  92. adam/commands/reaper/reaper_schedule_activate.py +6 -2
  93. adam/commands/reaper/reaper_schedule_start.py +1 -2
  94. adam/commands/reaper/reaper_schedule_stop.py +1 -2
  95. adam/commands/reaper/utils_reaper.py +10 -1
  96. adam/commands/repair/repair_scan.py +0 -2
  97. adam/commands/repair/repair_stop.py +0 -1
  98. adam/commands/{show/show.py → show.py} +12 -11
  99. adam/config.py +4 -5
  100. adam/embedded_params.py +1 -1
  101. adam/repl.py +22 -9
  102. adam/repl_commands.py +50 -42
  103. adam/repl_session.py +9 -1
  104. adam/repl_state.py +16 -1
  105. adam/sql/async_executor.py +62 -0
  106. adam/sql/lark_completer.py +286 -0
  107. adam/sql/lark_parser.py +604 -0
  108. adam/sql/qingl.lark +1076 -0
  109. adam/sso/cred_cache.py +2 -5
  110. adam/utils.py +216 -79
  111. adam/utils_k8s/app_clusters.py +11 -4
  112. adam/utils_k8s/app_pods.py +10 -5
  113. adam/utils_k8s/cassandra_clusters.py +8 -4
  114. adam/utils_k8s/cassandra_nodes.py +14 -5
  115. adam/utils_k8s/k8s.py +9 -0
  116. adam/utils_k8s/kube_context.py +1 -4
  117. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
  118. adam/utils_k8s/pods.py +83 -24
  119. adam/utils_k8s/statefulsets.py +5 -2
  120. adam/utils_local.py +78 -2
  121. adam/utils_repl/appendable_completer.py +6 -0
  122. adam/utils_repl/repl_completer.py +51 -4
  123. adam/utils_sqlite.py +3 -8
  124. adam/version.py +1 -1
  125. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  126. kaqing-2.0.214.dist-info/RECORD +272 -0
  127. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  128. teddy/__init__.py +0 -0
  129. teddy/lark_parser.py +436 -0
  130. teddy/lark_parser2.py +618 -0
  131. adam/commands/cql/cql_completions.py +0 -32
  132. adam/commands/export/export_select_x.py +0 -54
  133. adam/commands/logs.py +0 -37
  134. adam/commands/postgres/psql_completions.py +0 -11
  135. adam/commands/report.py +0 -61
  136. adam/commands/restart.py +0 -60
  137. adam/commands/show/show_processes.py +0 -49
  138. kaqing-2.0.184.dist-info/RECORD +0 -244
  139. kaqing-2.0.184.dist-info/top_level.txt +0 -1
  140. /adam/commands/{login.py → app/login.py} +0 -0
  141. /adam/commands/{show → cassandra}/__init__.py +0 -0
  142. /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
  143. /adam/commands/{watch.py → cassandra/watch.py} +0 -0
  144. /adam/commands/{param_get.py → config/param_get.py} +0 -0
  145. /adam/commands/{param_set.py → config/param_set.py} +0 -0
  146. /adam/commands/{issues.py → diag/issues.py} +0 -0
  147. /adam/commands/{pwd.py → fs/pwd.py} +0 -0
  148. /adam/commands/{shell.py → fs/shell.py} +0 -0
  149. /adam/commands/{show → fs}/show_host.py +0 -0
  150. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  151. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  152. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,52 @@
1
+ import click
2
+ import json
3
+
4
+ from adam.checks.check_result import CheckResult
5
+ from adam.checks.check_utils import run_checks
6
+ from adam.commands import extract_options
7
+ from adam.commands.command import Command
8
+ from adam.commands.commands_utils import kaqing_log_file
9
+ from adam.repl_state import ReplState
10
+ from adam.utils import log2
11
+
12
+ class GenerateReport(Command):
13
+ COMMAND = 'generate report'
14
+
15
+ # the singleton pattern
16
+ def __new__(cls, *args, **kwargs):
17
+ if not hasattr(cls, 'instance'): cls.instance = super(GenerateReport, cls).__new__(cls)
18
+
19
+ return cls.instance
20
+
21
+ def __init__(self, successor: Command=None):
22
+ super().__init__(successor)
23
+
24
+ def command(self):
25
+ return GenerateReport.COMMAND
26
+
27
+ def required(self):
28
+ return ReplState.NON_L
29
+
30
+ def run(self, cmd: str, state: ReplState):
31
+ if not(args := self.args(cmd)):
32
+ return super().run(cmd, state)
33
+
34
+ with self.validate(args, state) as (args, state):
35
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
36
+ results = run_checks(state.sts, state.namespace, state.pod, show_out=show_out)
37
+ output = CheckResult.report(results)
38
+
39
+ if state.in_repl:
40
+ with kaqing_log_file() as json_file:
41
+ json.dump(output, json_file, indent=2)
42
+ log2(f'Report stored in {json_file.name}.')
43
+ else:
44
+ click.echo(json.dumps(output, indent=2))
45
+
46
+ return output
47
+
48
+ def completion(self, state: ReplState):
49
+ return super().completion(state, {'-s': None})
50
+
51
+ def help(self, _: ReplState):
52
+ return f"{GenerateReport.COMMAND} [-s]\t generate report"
@@ -0,0 +1,11 @@
1
+ from adam.commands.export.export_databases import ExportDatabases
2
+ from adam.repl_state import ReplState
3
+ from adam.sql.lark_completer import LarkCompleter
4
+ from adam.utils_athena import Athena
5
+
6
+ def completions_x(state: ReplState):
7
+ return LarkCompleter(expandables={
8
+ 'tables': lambda x: ExportDatabases.table_names(state.export_session),
9
+ 'export-databases': lambda x: ExportDatabases.database_names(),
10
+ 'columns': lambda x: Athena.column_names(database=state.export_session, function='export'),
11
+ }, variant=ReplState.X).completions_for_nesting()
@@ -33,7 +33,8 @@ class DownloadExportSession(Command):
33
33
  return state
34
34
 
35
35
  def completion(self, state: ReplState):
36
- return super().completion(state, {session: None for session in ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import')})
36
+ return {}
37
+ # return super().completion(state, {session: None for session in ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import')})
37
38
 
38
39
  def help(self, _: ReplState):
39
40
  return f'{DownloadExportSession.COMMAND} <export-session-name>\t download csv files in export session'
@@ -1,12 +1,7 @@
1
1
  from adam.commands import extract_options
2
2
  from adam.commands.command import Command
3
- from adam.commands.cql.utils_cql import cassandra_keyspaces, cassandra_table_names
4
- from adam.commands.export.export_databases import ExportDatabases
5
3
  from adam.commands.export.exporter import export
6
4
  from adam.repl_state import ReplState, RequiredState
7
- from adam.sql.sql_completer import SqlCompleter, SqlVariant
8
- from adam.utils import log
9
- from adam.utils_k8s.statefulsets import StatefulSets
10
5
 
11
6
  class ExportTables(Command):
12
7
  COMMAND = 'export'
@@ -36,17 +31,6 @@ class ExportTables(Command):
36
31
  return exporter.export(args, export_only=export_only)
37
32
 
38
33
  def completion(self, state: ReplState):
39
- def sc():
40
- return SqlCompleter(lambda: cassandra_table_names(state), expandables={
41
- 'dml':'export',
42
- 'columns': lambda table: ['id', '*'],
43
- 'keyspaces': lambda: cassandra_keyspaces(state),
44
- 'export-dbs': lambda: ExportDatabases.database_names(),
45
- }, variant=SqlVariant.CQL)
46
-
47
- if super().completion(state):
48
- return {f'@{p}': {ExportTables.COMMAND: sc()} for p in StatefulSets.pod_names(state.sts, state.namespace)}
49
-
50
34
  return {}
51
35
 
52
36
  def help(self, _: ReplState):
@@ -1,14 +1,16 @@
1
1
  from collections.abc import Callable
2
2
  from datetime import datetime
3
+ from functools import partial
3
4
  import os
4
5
  import boto3
5
6
 
6
7
  from adam.commands.export.export_sessions import ExportSessions
7
8
  from adam.commands.export.importer import Importer
9
+ from adam.commands.export.utils_export import export_log_dir
8
10
  from adam.config import Config
9
11
  from adam.repl_session import ReplSession
10
12
  from adam.repl_state import ReplState
11
- from adam.utils import debug, tabulize, log2, ing, log_exc
13
+ from adam.utils import debug, log_timing, tabulize, log2, ing, log_exc
12
14
  from adam.utils_athena import Athena
13
15
  from adam.utils_sqlite import SQLite
14
16
 
@@ -31,7 +33,7 @@ class ExportDatabases:
31
33
 
32
34
  if Config().get('repl.history.push-cat-log-file', True):
33
35
  if log_file and ReplSession().prompt_session:
34
- ReplSession().prompt_session.history.append_string(f':sh cat {log_file}')
36
+ ReplSession().prompt_session.history.append_string(f':cat {log_file}')
35
37
 
36
38
  return cnt
37
39
 
@@ -111,7 +113,8 @@ class ExportDatabases:
111
113
  return list({n.split('_')[0] for n in SQLite.database_names()})
112
114
 
113
115
  def export_database_names():
114
- return list({n.split('_')[0] for n in Athena.database_names(LIKE)})
116
+ with log_timing('ExportDatabases.Athena.database_names'):
117
+ return list({n.split('_')[0] for n in Athena.database_names(LIKE)})
115
118
 
116
119
  def database_names_with_keyspace_cnt(importer: str = None):
117
120
  r = {}
@@ -191,20 +194,23 @@ class ExportDatabaseService:
191
194
  def __init__(self, handler: 'ExportDatabaseHandler'):
192
195
  self.handler = handler
193
196
 
194
- def sql(self, query: str, database: str = None, backgrounded = False):
197
+ def sql(self, query: str, database: str = None, backgrounded = False, export_log: str = None):
195
198
  if not database:
196
199
  database = self.handler.state.export_session
197
200
 
198
- def output(out: str):
199
- log_prefix = Config().get('export.log-prefix', '/tmp/qing')
200
- log_file = f'{log_prefix}-{datetime.now().strftime("%d%H%M%S")}-export.log'
201
+ def output(export_log: str, out: str):
202
+ # serving for 1. export log or 2. job log for the sampling select 10 rows afterward
203
+ flag = 'at'
204
+ if not export_log:
205
+ export_log = f'{export_log_dir()}/{datetime.now().strftime("%d%H%M%S")}-export.log'
206
+ flag = 'w'
201
207
 
202
- with open(log_file, 'w') as f:
208
+ with open(export_log, flag) as f:
203
209
  f.write(out)
204
210
 
205
- return log_file
211
+ return export_log
206
212
 
207
- ExportDatabases.run_query(query, database, output = output if backgrounded else None, show_query = not backgrounded)
213
+ ExportDatabases.run_query(query, database, output = partial(output, export_log) if backgrounded else None, show_query = not backgrounded)
208
214
 
209
215
  def drop(self, database: str):
210
216
  state = self.handler.state
@@ -1,12 +1,10 @@
1
- from adam.commands import extract_trailing_options, validate_args
2
1
  from adam.commands.command import Command
3
- from adam.commands.export.export_databases import ExportDatabases, export_db
2
+ from adam.commands.export.completions_x import completions_x
4
3
  from adam.repl_state import ReplState, RequiredState
5
- from adam.sql.sql_completer import SqlCompleter, SqlVariant
6
- from adam.utils_athena import Athena
7
4
 
5
+ # No action body, only for a help entry and auto-completion
8
6
  class ExportSelect(Command):
9
- COMMAND = '.select'
7
+ COMMAND = 'select_on_x'
10
8
 
11
9
  # the singleton pattern
12
10
  def __new__(cls, *args, **kwargs):
@@ -23,37 +21,14 @@ class ExportSelect(Command):
23
21
  def required(self):
24
22
  return RequiredState.EXPORT_DB
25
23
 
26
- def run(self, cmd: str, state: ReplState):
27
- if not(args := self.args(cmd)):
28
- return super().run(cmd, state)
29
-
30
- with self.validate(args, state) as (args, state):
31
- with extract_trailing_options(args, '&') as (args, backgrounded):
32
- with validate_args(args, state, name='SQL statement') as query:
33
- with export_db(state) as dbs:
34
- dbs.sql(f'select {query}', backgrounded=backgrounded)
35
-
36
- return state
37
-
38
24
  def completion(self, state: ReplState):
39
- if not state.export_session:
25
+ if state.device != ReplState.X:
40
26
  return {}
41
27
 
42
- db = state.export_session
43
-
44
- # warm up the caches first time when x: drive is accessed
45
- ExportDatabases.table_names(db)
46
- Athena.column_names(database=db, function='export')
47
- Athena.column_names(partition_cols_only=True, database=db, function='export')
28
+ if state.export_session:
29
+ return completions_x(state)
48
30
 
49
- return {ExportSelect.COMMAND: SqlCompleter(
50
- lambda: ExportDatabases.table_names(db),
51
- dml='select',
52
- expandables={
53
- 'columns':lambda table: Athena.column_names(database=db, function='export'),
54
- },
55
- variant=SqlVariant.ATHENA
56
- )}
31
+ return {}
57
32
 
58
33
  def help(self, _: ReplState):
59
- return f'.<sql-select-statements>\t run queries on export database'
34
+ return f'<sql-select-statements>\t run queries on export database'
@@ -3,14 +3,14 @@ import os
3
3
  import re
4
4
 
5
5
  from adam.commands.export.importer import Importer
6
- from adam.commands.export.utils_export import ExportTableStatus, csv_dir, find_files
6
+ from adam.commands.export.utils_export import ExportTableStatus, csv_dir, export_log_dir, find_files, os_system_exec
7
7
  from adam.config import Config
8
8
  from adam.repl_state import ReplState
9
9
  from adam.utils import log2, tabulize, log, parallelize
10
10
  from adam.utils_k8s.cassandra_nodes import CassandraNodes
11
- from adam.utils_k8s.pods import Pods, log_prefix
11
+ from adam.utils_k8s.pods import Pods
12
12
  from adam.utils_k8s.statefulsets import StatefulSets
13
- from adam.utils_local import local_tmp_dir
13
+ from adam.utils_local import local_downloads_dir
14
14
 
15
15
  class ExportSessions:
16
16
  def clear_export_session_cache():
@@ -36,13 +36,13 @@ class ExportSessions:
36
36
 
37
37
  prefix = Importer.prefix_from_importer(importer)
38
38
 
39
- log_files: list[str] = find_files(pod, namespace, f'{log_prefix()}-{prefix}*_*.log*')
39
+ log_files: list[str] = find_files(pod, namespace, f'{export_log_dir()}/{prefix}*_*.log*')
40
40
 
41
41
  if not log_files:
42
42
  return {}
43
43
 
44
44
  for log_file in log_files[:limit]:
45
- m = re.match(f'{log_prefix()}-(.*?)_.*\.log?(.*)', log_file)
45
+ m = re.match(f'{export_log_dir()}/([ces].*?)_.*\.log?(.*)', log_file)
46
46
  if m:
47
47
  s = m.group(1)
48
48
  state = m.group(2) # '', '.pending_import', '.done'
@@ -66,7 +66,8 @@ class ExportSessions:
66
66
  pod = StatefulSets.pod_names(sts, namespace)[0]
67
67
 
68
68
  CassandraNodes.exec(pod, namespace, f'rm -rf {csv_dir()}/*', show_out=Config().is_debug(), shell='bash')
69
- CassandraNodes.exec(pod, namespace, f'rm -rf {log_prefix()}-*.log*', show_out=Config().is_debug(), shell='bash')
69
+ cmd = f'rm -rf {export_log_dir()}/*.log*'
70
+ os_system_exec(cmd, show_out=Config().is_debug())
70
71
 
71
72
  return True
72
73
 
@@ -102,17 +103,18 @@ class ExportSessions:
102
103
  csv_cnt = 0
103
104
  log_cnt = 0
104
105
 
105
- log_files: list[str] = find_files(pod, namespace, f'{log_prefix()}-{session}_*.log*')
106
+ log_files: list[str] = find_files(pod, namespace, f'{export_log_dir()}/{session}_*.log*')
106
107
 
107
108
  for log_file in log_files:
108
- m = re.match(f'{log_prefix()}-{session}_(.*?)\.(.*?)\.log.*', log_file)
109
+ m = re.match(f'{export_log_dir()}/{session}_(.*?)\.(.*?)\.log.*', log_file)
109
110
  if m:
110
111
  table = m.group(2)
111
112
 
112
113
  CassandraNodes.exec(pod, namespace, f'rm -rf {csv_dir()}/{session}_{table}', show_out=not multi_tables, shell='bash')
113
114
  csv_cnt += 1
114
115
 
115
- CassandraNodes.exec(pod, namespace, f'rm -rf {log_file}', show_out=not multi_tables, shell='bash')
116
+ cmd = f'rm -rf {log_file}'
117
+ os_system_exec(cmd, show_out=not multi_tables)
116
118
  log_cnt += 1
117
119
 
118
120
  return csv_cnt, log_cnt
@@ -142,8 +144,7 @@ class ExportSessions:
142
144
  def download_csv(table):
143
145
  from_path: str = table.csv_file
144
146
 
145
- to_path = from_path.replace(csv_dir(), local_tmp_dir())
146
- os.makedirs(os.path.dirname(to_path), exist_ok=True)
147
+ to_path = from_path.replace(csv_dir(), local_downloads_dir())
147
148
  Pods.download_file(pod, 'cassandra', namespace, from_path, to_path)
148
149
 
149
150
  log2(f'[{session}] Downloaded to {to_path}.')
@@ -1,6 +1,6 @@
1
1
  from adam.commands import validate_args
2
2
  from adam.commands.command import Command
3
- from adam.commands.export.export_databases import ExportDatabases, export_db
3
+ from adam.commands.export.export_databases import export_db
4
4
  from adam.repl_state import ReplState
5
5
  from adam.utils import log2
6
6
 
@@ -20,7 +20,7 @@ class ExportUse(Command):
20
20
  return ExportUse.COMMAND
21
21
 
22
22
  def required(self):
23
- return [ReplState.C, ReplState.X]
23
+ return [ReplState.C]
24
24
 
25
25
  def run(self, cmd: str, state: ReplState):
26
26
  if not(args := self.args(cmd)):
@@ -43,7 +43,7 @@ class ExportUse(Command):
43
43
  return state
44
44
 
45
45
  def completion(self, state: ReplState):
46
- return super().completion(state, {n: None for n in ExportDatabases.database_names()})
46
+ return {}
47
47
 
48
48
  def help(self, _: ReplState):
49
49
  return f'{ExportUse.COMMAND} <export-database-name>\t use export database'
@@ -0,0 +1,48 @@
1
+ from adam.commands import extract_trailing_options, validate_args
2
+ from adam.commands.command import Command
3
+ from adam.commands.export.completions_x import completions_x
4
+ from adam.commands.export.export_databases import export_db
5
+ from adam.repl_state import ReplState, RequiredState
6
+
7
+ class ExportXSelect(Command):
8
+ COMMAND = 'xelect'
9
+
10
+ # the singleton pattern
11
+ def __new__(cls, *args, **kwargs):
12
+ if not hasattr(cls, 'instance'): cls.instance = super(ExportXSelect, cls).__new__(cls)
13
+
14
+ return cls.instance
15
+
16
+ def __init__(self, successor: Command=None):
17
+ super().__init__(successor)
18
+
19
+ def command(self):
20
+ return ExportXSelect.COMMAND
21
+
22
+ def required(self):
23
+ return RequiredState.EXPORT_DB
24
+
25
+ def run(self, cmd: str, state: ReplState):
26
+ if not(args := self.args(cmd)):
27
+ return super().run(cmd, state)
28
+
29
+ with self.validate(args, state) as (args, state):
30
+ with extract_trailing_options(args, '&') as (args, backgrounded):
31
+ with validate_args(args, state, name='SQL statement') as query:
32
+ with export_db(state) as dbs:
33
+ dbs.sql(f'select {query}', backgrounded=backgrounded)
34
+
35
+ return state
36
+
37
+ def completion(self, state: ReplState):
38
+ if state.device != ReplState.C:
39
+ return {}
40
+
41
+ if not state.export_session:
42
+ return {}
43
+
44
+ # add only xelect completions to c: drive from lark
45
+ return {ExportXSelect.COMMAND: completions_x(state)[ExportXSelect.COMMAND]}
46
+
47
+ def help(self, _: ReplState):
48
+ return f'xelect...\t run queries on export database'