Skip to content

Commit 8abee19

Browse files
committed
add source code.
1 parent 98744f9 commit 8abee19

9 files changed

+439
-2
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*cache*
2+
dist/
3+
*sqlite
4+
*db
5+
*egg-info

README.md

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,34 @@
1-
# aoi
2-
SQLITE3 cli based on python sqlite3 module.
1+
# 🍥 aoi
2+
A simple python based sqlite3 CLI.
3+
4+
---
5+
6+
## Usage
7+
```sh
8+
$python -m aoi [-c "path to connect"]
9+
```
10+
using the -c/--connect option will connect the application to the provided db file path.
11+
12+
If no option is provided, `:memory:` ( in memory database ) will be used.
13+
14+
## Additional Features
15+
16+
Apart from normal sqlite quries you can run the following commands within the CLI:
17+
18+
`:h/:help`: Get help for commands.
19+
20+
`:q/:quit`: Exit the CLI.
21+
22+
`:r/:recent [amount=5]`: Show last [amount=5] queries.
23+
24+
---
25+
## Requirements
26+
* Python (3.8 or later)
27+
28+
Installing aoi in your environment using pip, poetry or any favourable package manager
29+
```sh
30+
# pip
31+
$python -m pip install git+https://github.com/sarthhh/aoi.git
32+
# poetry
33+
$poetry add git+https://github.com/sarthhh/aoi.git
34+
```

aoi/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1.5"

aoi/__main__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from aoi.base import main
2+
3+
main()

aoi/_misc.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import annotations
2+
3+
import typing
4+
5+
import colorama
6+
7+
if typing.TYPE_CHECKING:
8+
from aoi.base import Session
9+
10+
11+
UNDEFINED = object()
12+
EMOJI = "\U0001f365"
13+
14+
cmds: dict[str, str] = {
15+
":q | :quit": "Stops the cli session.",
16+
":h | :help": "Shows this help message.",
17+
":r | :recent": "List recently used commands.",
18+
}
19+
20+
21+
def error_print(msg: str) -> None:
22+
print(colorama.Fore.LIGHTMAGENTA_EX, msg, colorama.Style.RESET_ALL, sep="")
23+
24+
25+
def process_commands(data: str, session: Session) -> typing.Any:
26+
if data in (":q", ":quit"):
27+
session.stop()
28+
elif data in (":h", ":help"):
29+
[
30+
print(
31+
colorama.Style.BRIGHT,
32+
colorama.Fore.GREEN,
33+
f"[{cmd}]",
34+
colorama.Style.RESET_ALL,
35+
": ",
36+
colorama.Fore.CYAN,
37+
info,
38+
colorama.Style.RESET_ALL,
39+
sep="",
40+
end="\n",
41+
)
42+
for cmd, info in cmds.items()
43+
]
44+
elif data.startswith(":recent"):
45+
if data[7:] and data[7:].strip().isnumeric():
46+
print("\n".join(session.recent_queries[-int(data[7:]) :]))
47+
else:
48+
print("\n".join(session.recent_queries[-5:]))
49+
50+
elif data.startswith(":r"):
51+
if data[3:] and data[3:].strip().isnumeric():
52+
print("\n".join(session.recent_queries[-int(data[3:]) :]))
53+
else:
54+
print("\n".join(session.recent_queries[-5:]))
55+
56+
else:
57+
error_print(f"No command named {data} found, use :h to get a list of all commands")

aoi/base.py

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import argparse
2+
import sys
3+
4+
import colorama
5+
6+
from aoi._misc import process_commands
7+
from aoi.sqlite import connect, run_sql
8+
9+
parser = argparse.ArgumentParser("aoi", usage="aoi *[options]", description="SQLITE3 in CLI.", add_help=True)
10+
11+
parser.add_argument("-c", "--connect", help="The sqlite file to connect.")
12+
parser.add_argument("-v", "--version", help="Check version of the application.", action="store_true")
13+
14+
15+
class Args(argparse.Namespace):
16+
connect: str | None
17+
version: str | None
18+
19+
20+
class Session:
21+
recent_queries: list[str] = []
22+
running: bool
23+
24+
def __init__(self, file: str) -> None:
25+
self.file = file
26+
27+
connect(file)
28+
29+
def start(self) -> None:
30+
self.running = True
31+
print(
32+
colorama.Fore.BLUE,
33+
colorama.Style.BRIGHT,
34+
"Welcome to ",
35+
colorama.Fore.CYAN,
36+
"\U0001f365 aoi",
37+
colorama.Fore.BLUE,
38+
"!",
39+
colorama.Style.RESET_ALL,
40+
f" [connected to: \033[1;33m{self.file}\033[0m]",
41+
sep="",
42+
end="\n",
43+
)
44+
print(
45+
colorama.Fore.LIGHTBLUE_EX,
46+
"type :h for list of inbuilt commands.",
47+
colorama.Style.RESET_ALL,
48+
sep="",
49+
)
50+
51+
while self.running is True:
52+
data = input("> ")
53+
if data.startswith(":"):
54+
process_commands(data, self)
55+
continue
56+
while not data.strip().endswith(";"):
57+
data += f" {input('- ')}"
58+
59+
run_sql(data, self)
60+
raise KeyboardInterrupt
61+
62+
def stop(self) -> None:
63+
self.running = False
64+
65+
66+
def main() -> None:
67+
args: Args = parser.parse_args()
68+
file = args.connect or ":memory:"
69+
if args.version and args.connect is None:
70+
print(
71+
colorama.Fore.BLUE,
72+
colorama.Style.BRIGHT,
73+
"aoi\U0001f365 version: ",
74+
colorama.Fore.GREEN,
75+
colorama.Style.NORMAL,
76+
"0.1.0\n",
77+
colorama.Fore.BLUE,
78+
colorama.Style.BRIGHT,
79+
"Python version: ",
80+
colorama.Style.NORMAL,
81+
colorama.Fore.GREEN,
82+
sys.version,
83+
colorama.Style.RESET_ALL,
84+
sep="",
85+
)
86+
return
87+
try:
88+
(session := Session(file)).start()
89+
except KeyboardInterrupt:
90+
print(
91+
"\n" if session.running else "",
92+
colorama.Fore.BLUE,
93+
colorama.Style.BRIGHT,
94+
"Thank you for using ",
95+
colorama.Fore.CYAN,
96+
"\U0001f365 aoi",
97+
colorama.Fore.BLUE,
98+
"!",
99+
sep="",
100+
)

aoi/sqlite.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from __future__ import annotations
2+
3+
import sqlite3
4+
import typing
5+
6+
import colorama
7+
8+
from aoi._misc import UNDEFINED, error_print
9+
10+
if typing.TYPE_CHECKING:
11+
from aoi.base import Session
12+
13+
14+
connection: sqlite3.Connection = UNDEFINED
15+
16+
17+
def connect(path: str) -> None:
18+
global connection
19+
try:
20+
connection = sqlite3.connect(path)
21+
except sqlite3.OperationalError:
22+
print(error_print(f"[Operational Error:] Unable to connect to the path: {path}"))
23+
raise KeyboardInterrupt
24+
25+
26+
def _success() -> None:
27+
print(colorama.Style.BRIGHT, colorama.Fore.GREEN, "Executed successfully.", colorama.Style.RESET_ALL, sep="")
28+
29+
30+
def run_sql(query: str, session: Session) -> typing.Any:
31+
session.recent_queries.append(query)
32+
try:
33+
cursor = connection.execute(query)
34+
print(data) if (data := cursor.fetchall()) else _success()
35+
except sqlite3.OperationalError as e:
36+
error_print(f"[Operationl Error:] {e.args[0]}")

0 commit comments

Comments
 (0)