Skip to content

Commit 08b3357

Browse files
committed
add keybindings to insert server date/datetime
* C-o d: date * C-o C-d: quoted date * C-o t: datetime * C-o C-t: quoted datetime all in terms of NOW() on the server to which we are connected.
1 parent 10ba4bc commit 08b3357

File tree

7 files changed

+124
-0
lines changed

7 files changed

+124
-0
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Features
66

77
* Support SSL query parameters on DSNs.
88
* More information and care on KeyboardInterrupt.
9+
* Keybindings to insert current date/datetime.
910

1011
Internal
1112
--------

doc/key_bindings.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,27 @@ C-x u (Emacs-mode)
6363
Unprettify and dedent current statement, usually into one line.
6464

6565
Only accepts buffers containing single SQL statements.
66+
67+
##################
68+
C-o d (Emacs-mode)
69+
##################
70+
71+
Insert the current date at cursor, defined by NOW() on the server.
72+
73+
####################
74+
C-o C-d (Emacs-mode)
75+
####################
76+
77+
Insert the quoted current date at cursor.
78+
79+
##################
80+
C-o t (Emacs-mode)
81+
##################
82+
83+
Insert the current datetime at cursor.
84+
85+
####################
86+
C-o C-t (Emacs-mode)
87+
####################
88+
89+
Insert the quoted current datetime at cursor.

mycli/key_bindings.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from prompt_toolkit.filters import completion_is_selected, emacs_mode
55
from prompt_toolkit.key_binding import KeyBindings
66

7+
from mycli import shortcuts
78
from mycli.packages.toolkit.fzf import search_history
89

910
_logger = logging.getLogger(__name__)
@@ -102,6 +103,42 @@ def _(event):
102103
cursorpos_abs -= 1
103104
b.cursor_position = min(cursorpos_abs, len(b.text))
104105

106+
@kb.add("c-o", "d", filter=emacs_mode)
107+
def _(event):
108+
"""
109+
Insert the current date.
110+
"""
111+
_logger.debug("Detected <C-o d> key.")
112+
113+
event.app.current_buffer.insert_text(shortcuts.server_date(mycli.sqlexecute))
114+
115+
@kb.add("c-o", "c-d", filter=emacs_mode)
116+
def _(event):
117+
"""
118+
Insert the quoted current date.
119+
"""
120+
_logger.debug("Detected <C-o C-d> key.")
121+
122+
event.app.current_buffer.insert_text(shortcuts.server_date(mycli.sqlexecute, quoted=True))
123+
124+
@kb.add("c-o", "t", filter=emacs_mode)
125+
def _(event):
126+
"""
127+
Insert the current datetime.
128+
"""
129+
_logger.debug("Detected <C-o t> key.")
130+
131+
event.app.current_buffer.insert_text(shortcuts.server_datetime(mycli.sqlexecute))
132+
133+
@kb.add("c-o", "c-t", filter=emacs_mode)
134+
def _(event):
135+
"""
136+
Insert the quoted current datetime.
137+
"""
138+
_logger.debug("Detected <C-o C-t> key.")
139+
140+
event.app.current_buffer.insert_text(shortcuts.server_datetime(mycli.sqlexecute, quoted=True))
141+
105142
@kb.add("c-r", filter=emacs_mode)
106143
def _(event):
107144
"""Search history using fzf or default reverse incremental search."""

mycli/shortcuts.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
def server_date(sqlexecute, quoted: bool = False) -> str:
2+
server_date_str = sqlexecute.now().strftime('%Y-%m-%d')
3+
if quoted:
4+
return f"'{server_date_str}'"
5+
else:
6+
return server_date_str
7+
8+
9+
def server_datetime(sqlexecute, quoted: bool = False) -> str:
10+
server_datetime_str = sqlexecute.now().strftime('%Y-%m-%d %H:%M:%S')
11+
if quoted:
12+
return f"'{server_datetime_str}'"
13+
else:
14+
return server_datetime_str

mycli/sqlexecute.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class SQLExecute(object):
9494
where table_schema = '%s'
9595
order by table_name,ordinal_position"""
9696

97+
now_query = """SELECT NOW()"""
98+
9799
def __init__(
98100
self,
99101
database,
@@ -393,6 +395,12 @@ def users(self):
393395
for row in cur:
394396
yield row
395397

398+
def now(self):
399+
with self.conn.cursor() as cur:
400+
_logger.debug("Now Query. sql: %r", self.now_query)
401+
cur.execute(self.now_query)
402+
return cur.fetchone()[0]
403+
396404
def get_connection_id(self):
397405
if not self.connection_id:
398406
self.reset_connection_id()

test/features/basic_commands.feature

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Feature: run the cli,
22
call the help command,
3+
check our application name,
4+
insert the date,
35
exit the cli
46

57
Scenario: run "\?" command
@@ -14,6 +16,10 @@ Feature: run the cli,
1416
When we run query to check application_name
1517
then we see found
1618

19+
Scenario: insert the date
20+
When we send "ctrl + o, ctrl + d"
21+
then we see the date
22+
1723
Scenario: run the cli and exit
1824
When we send "ctrl + d"
1925
then dbcli exits

test/features/steps/basic_commands.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
"""
77

8+
import datetime
89
import tempfile
910
from textwrap import dedent
1011

@@ -29,6 +30,16 @@ def step_ctrl_d(context):
2930
context.exit_sent = True
3031

3132

33+
@when('we send "ctrl + o, ctrl + d"')
34+
def step_ctrl_o_ctrl_d(context):
35+
"""Send ctrl + o, ctrl + d to insert the quoted date."""
36+
context.cli.send("SELECT ")
37+
context.cli.sendcontrol("o")
38+
context.cli.sendcontrol("d")
39+
context.cli.send(" AS dt")
40+
context.cli.sendline("")
41+
42+
3243
@when(r'we send "\?" command')
3344
def step_send_help(context):
3445
r"""Send \?
@@ -75,6 +86,29 @@ def step_see_found(context):
7586
)
7687

7788

89+
@then("we see the date")
90+
def step_see_date(context):
91+
# There are some edge cases in which this test could fail,
92+
# such as running near midnight when the test database has
93+
# a different TZ setting than the system.
94+
date_str = datetime.datetime.now().strftime("%Y-%m-%d")
95+
wrappers.expect_exact(
96+
context,
97+
context.conf["pager_boundary"]
98+
+ "\r"
99+
+ dedent(f"""
100+
+------------+\r
101+
| dt |\r
102+
+------------+\r
103+
| {date_str} |\r
104+
+------------+\r
105+
\r
106+
""")
107+
+ context.conf["pager_boundary"],
108+
timeout=5,
109+
)
110+
111+
78112
@then("we confirm the destructive warning")
79113
def step_confirm_destructive_command(context): # noqa
80114
"""Confirm destructive command."""

0 commit comments

Comments
 (0)