Merging upstream version 1.14.2.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
a842e453d1
commit
3b8f21e56b
18 changed files with 766 additions and 97 deletions
187
litecli/main.py
187
litecli/main.py
|
@ -1,52 +1,50 @@
|
|||
from __future__ import unicode_literals
|
||||
from __future__ import print_function
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import threading
|
||||
from time import time
|
||||
import traceback
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from io import open
|
||||
from collections import namedtuple
|
||||
from sqlite3 import OperationalError, sqlite_version
|
||||
import shutil
|
||||
from time import time
|
||||
|
||||
from cli_helpers.tabular_output import TabularOutputFormatter
|
||||
from cli_helpers.tabular_output import preprocessors
|
||||
import click
|
||||
import sqlparse
|
||||
from cli_helpers.tabular_output import TabularOutputFormatter, preprocessors
|
||||
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||
from prompt_toolkit.completion import DynamicCompleter
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
|
||||
from prompt_toolkit.shortcuts import PromptSession, CompleteStyle
|
||||
from prompt_toolkit.document import Document
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
|
||||
from prompt_toolkit.filters import HasFocus, IsDone
|
||||
from prompt_toolkit.formatted_text import ANSI
|
||||
from prompt_toolkit.history import FileHistory
|
||||
from prompt_toolkit.layout.processors import (
|
||||
HighlightMatchingBracketProcessor,
|
||||
ConditionalProcessor,
|
||||
HighlightMatchingBracketProcessor,
|
||||
)
|
||||
from prompt_toolkit.lexers import PygmentsLexer
|
||||
from prompt_toolkit.history import FileHistory
|
||||
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||
from prompt_toolkit.shortcuts import CompleteStyle, PromptSession
|
||||
|
||||
from .packages.special.main import NO_QUERY
|
||||
from .packages.prompt_utils import confirm, confirm_destructive_query
|
||||
from .packages import special
|
||||
from .sqlcompleter import SQLCompleter
|
||||
from .clitoolbar import create_toolbar_tokens_func
|
||||
from .clistyle import style_factory, style_factory_output
|
||||
from .sqlexecute import SQLExecute
|
||||
from .__init__ import __version__
|
||||
from .clibuffer import cli_is_multiline
|
||||
from .clistyle import style_factory, style_factory_output
|
||||
from .clitoolbar import create_toolbar_tokens_func
|
||||
from .completion_refresher import CompletionRefresher
|
||||
from .config import config_location, ensure_dir_exists, get_config
|
||||
from .key_bindings import cli_bindings
|
||||
from .lexer import LiteCliLexer
|
||||
from .__init__ import __version__
|
||||
from .packages import special
|
||||
from .packages.filepaths import dir_path_exists
|
||||
|
||||
import itertools
|
||||
from .packages.prompt_utils import confirm, confirm_destructive_query
|
||||
from .packages.special.main import NO_QUERY
|
||||
from .sqlcompleter import SQLCompleter
|
||||
from .sqlexecute import SQLExecute
|
||||
|
||||
click.disable_unicode_literals_warning = True
|
||||
|
||||
|
@ -385,6 +383,47 @@ class LiteCli(object):
|
|||
def show_suggestion_tip():
|
||||
return iterations < 2
|
||||
|
||||
def output_res(res, start):
|
||||
result_count = 0
|
||||
mutating = False
|
||||
for title, cur, headers, status in res:
|
||||
logger.debug("headers: %r", headers)
|
||||
logger.debug("rows: %r", cur)
|
||||
logger.debug("status: %r", status)
|
||||
threshold = 1000
|
||||
if is_select(status) and cur and cur.rowcount > threshold:
|
||||
self.echo(
|
||||
"The result set has more than {} rows.".format(threshold),
|
||||
fg="red",
|
||||
)
|
||||
if not confirm("Do you want to continue?"):
|
||||
self.echo("Aborted!", err=True, fg="red")
|
||||
break
|
||||
|
||||
if self.auto_vertical_output:
|
||||
max_width = self.prompt_app.output.get_size().columns
|
||||
else:
|
||||
max_width = None
|
||||
|
||||
formatted = self.format_output(title, cur, headers, special.is_expanded_output(), max_width)
|
||||
|
||||
t = time() - start
|
||||
try:
|
||||
if result_count > 0:
|
||||
self.echo("")
|
||||
try:
|
||||
self.output(formatted, status)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
self.echo("Time: %0.03fs" % t)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
start = time()
|
||||
result_count += 1
|
||||
mutating = mutating or is_mutating(status)
|
||||
return mutating
|
||||
|
||||
def one_iteration(text=None):
|
||||
if text is None:
|
||||
try:
|
||||
|
@ -402,6 +441,24 @@ class LiteCli(object):
|
|||
self.echo(str(e), err=True, fg="red")
|
||||
return
|
||||
|
||||
if special.is_llm_command(text):
|
||||
try:
|
||||
start = time()
|
||||
cur = self.sqlexecute.conn.cursor()
|
||||
context, sql = special.handle_llm(text, cur)
|
||||
if context:
|
||||
click.echo(context)
|
||||
text = self.prompt_app.prompt(default=sql)
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
except special.FinishIteration as e:
|
||||
return output_res(e.results, start) if e.results else None
|
||||
except RuntimeError as e:
|
||||
logger.error("sql: %r, error: %r", text, e)
|
||||
logger.error("traceback: %r", traceback.format_exc())
|
||||
self.echo(str(e), err=True, fg="red")
|
||||
return
|
||||
|
||||
if not text.strip():
|
||||
return
|
||||
|
||||
|
@ -415,9 +472,6 @@ class LiteCli(object):
|
|||
self.echo("Wise choice!")
|
||||
return
|
||||
|
||||
# Keep track of whether or not the query is mutating. In case
|
||||
# of a multi-statement query, the overall query is considered
|
||||
# mutating if any one of the component statements is mutating
|
||||
mutating = False
|
||||
|
||||
try:
|
||||
|
@ -434,44 +488,11 @@ class LiteCli(object):
|
|||
res = sqlexecute.run(text)
|
||||
self.formatter.query = text
|
||||
successful = True
|
||||
result_count = 0
|
||||
for title, cur, headers, status in res:
|
||||
logger.debug("headers: %r", headers)
|
||||
logger.debug("rows: %r", cur)
|
||||
logger.debug("status: %r", status)
|
||||
threshold = 1000
|
||||
if is_select(status) and cur and cur.rowcount > threshold:
|
||||
self.echo(
|
||||
"The result set has more than {} rows.".format(threshold),
|
||||
fg="red",
|
||||
)
|
||||
if not confirm("Do you want to continue?"):
|
||||
self.echo("Aborted!", err=True, fg="red")
|
||||
break
|
||||
|
||||
if self.auto_vertical_output:
|
||||
max_width = self.prompt_app.output.get_size().columns
|
||||
else:
|
||||
max_width = None
|
||||
|
||||
formatted = self.format_output(title, cur, headers, special.is_expanded_output(), max_width)
|
||||
|
||||
t = time() - start
|
||||
try:
|
||||
if result_count > 0:
|
||||
self.echo("")
|
||||
try:
|
||||
self.output(formatted, status)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
self.echo("Time: %0.03fs" % t)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
start = time()
|
||||
result_count += 1
|
||||
mutating = mutating or is_mutating(status)
|
||||
special.unset_once_if_written()
|
||||
# Keep track of whether or not the query is mutating. In case
|
||||
# of a multi-statement query, the overall query is considered
|
||||
# mutating if any one of the component statements is mutating
|
||||
mutating = output_res(res, start)
|
||||
special.unset_pipe_once_if_written()
|
||||
except EOFError as e:
|
||||
raise e
|
||||
|
@ -735,20 +756,32 @@ class LiteCli(object):
|
|||
return self.completer.get_completions(Document(text=text, cursor_position=cursor_positition), None)
|
||||
|
||||
def get_prompt(self, string):
|
||||
self.logger.debug("Getting prompt")
|
||||
self.logger.debug("Getting prompt %r", string)
|
||||
sqlexecute = self.sqlexecute
|
||||
now = datetime.now()
|
||||
string = string.replace("\\d", sqlexecute.dbname or "(none)")
|
||||
string = string.replace("\\f", os.path.basename(sqlexecute.dbname or "(none)"))
|
||||
string = string.replace("\\n", "\n")
|
||||
string = string.replace("\\D", now.strftime("%a %b %d %H:%M:%S %Y"))
|
||||
string = string.replace("\\m", now.strftime("%M"))
|
||||
string = string.replace("\\P", now.strftime("%p"))
|
||||
string = string.replace("\\R", now.strftime("%H"))
|
||||
string = string.replace("\\r", now.strftime("%I"))
|
||||
string = string.replace("\\s", now.strftime("%S"))
|
||||
string = string.replace("\\_", " ")
|
||||
return string
|
||||
|
||||
# Prepare the replacements dictionary
|
||||
replacements = {
|
||||
r"\d": sqlexecute.dbname or "(none)",
|
||||
r"\f": os.path.basename(sqlexecute.dbname or "(none)"),
|
||||
r"\n": "\n",
|
||||
r"\D": now.strftime("%a %b %d %H:%M:%S %Y"),
|
||||
r"\m": now.strftime("%M"),
|
||||
r"\P": now.strftime("%p"),
|
||||
r"\R": now.strftime("%H"),
|
||||
r"\r": now.strftime("%I"),
|
||||
r"\s": now.strftime("%S"),
|
||||
r"\_": " ",
|
||||
}
|
||||
# Compile a regex pattern that matches any of the keys in replacements
|
||||
pattern = re.compile("|".join(re.escape(key) for key in replacements.keys()))
|
||||
|
||||
# Define the replacement function
|
||||
def replacer(match):
|
||||
return replacements[match.group(0)]
|
||||
|
||||
# Perform the substitution
|
||||
return pattern.sub(replacer, string)
|
||||
|
||||
def run_query(self, query, new_line=True):
|
||||
"""Runs *query*."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue