SQLPyHelper 0.1.4__tar.gz → 0.1.5__tar.gz

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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SQLPyHelper
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: A simple SQL database helper package for Python.
5
5
  Home-page: https://github.com/adebayopeter/sqlpyhelper
6
6
  Author: Adebayo Olaonipekun
@@ -32,12 +32,12 @@ Requires-Dist: mysql-connector-python; extra == "mysql"
32
32
  Provides-Extra: sqlserver
33
33
  Requires-Dist: pyodbc; extra == "sqlserver"
34
34
  Provides-Extra: oracle
35
- Requires-Dist: cx_Oracle; extra == "oracle"
35
+ Requires-Dist: oracledb; extra == "oracle"
36
36
  Provides-Extra: all
37
37
  Requires-Dist: psycopg2; extra == "all"
38
38
  Requires-Dist: mysql-connector-python; extra == "all"
39
39
  Requires-Dist: pyodbc; extra == "all"
40
- Requires-Dist: cx_Oracle; extra == "all"
40
+ Requires-Dist: oracledb; extra == "all"
41
41
  Dynamic: author
42
42
  Dynamic: author-email
43
43
  Dynamic: classifier
@@ -60,9 +60,17 @@ Dynamic: summary
60
60
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/adebayopeter/sqlpyhelper/blob/main/LICENSE)
61
61
  [![GitHub stars](https://img.shields.io/github/stars/adebayopeter/sqlpyhelper?style=social)](https://github.com/adebayopeter/sqlpyhelper)
62
62
 
63
- # 📌 SQLPyHelper v.0.1.4 🚀
63
+ SQLPyHelper is a lightweight Python library that gives you a single, consistent API across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** — without the overhead of an ORM.
64
64
 
65
- A Python library for simplified database interactions across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle**. SQLPyHelper provides an intuitive API for handling queries, connection pooling, transactions, logging, and backups efficiently.
65
+ If you need to run queries, manage transactions, pool connections, or back up tables across multiple database types without learning SQLAlchemy's abstraction layer or wiring up five different drivers manually, SQLPyHelper handles that boilerplate for you.
66
+
67
+ ```python
68
+ # Works identically across all five supported databases
69
+ with SQLPyHelper(db_type="postgres", host="localhost", user="user",
70
+ password="pass", database="mydb") as db:
71
+ db.execute_query("INSERT INTO orders (item) VALUES (%s)", ("Laptop",))
72
+ results = db.fetch_all()
73
+ ```
66
74
 
67
75
  ## 📖 Table of Contents
68
76
  - [🚀 Features](#-features)
@@ -81,7 +89,7 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
81
89
 
82
90
  ---
83
91
 
84
- ## 🚀 Features in v0.1.3
92
+ ## 🚀 Features in v0.1.4
85
93
  - Unified connection pooling for multiple databases.
86
94
  - Automatic reconnection for lost connections.
87
95
  - Transaction support (BEGIN, ROLLBACK, COMMIT).
@@ -92,10 +100,21 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
92
100
 
93
101
  ---
94
102
  ## 📦 Installation
95
- #### Install via PyPI:
103
+
104
+ Install the base package (includes SQLite support out of the box):
96
105
  ```sh
97
106
  pip install sqlpyhelper
98
107
  ```
108
+
109
+ Install with your database driver:
110
+ ```sh
111
+ pip install sqlpyhelper[postgres] # PostgreSQL
112
+ pip install sqlpyhelper[mysql] # MySQL
113
+ pip install sqlpyhelper[sqlserver] # SQL Server
114
+ pip install sqlpyhelper[oracle] # Oracle
115
+ pip install sqlpyhelper[all] # All databases
116
+ ```
117
+
99
118
  📌 Package on PyPI: [SQLPyHelper on PyPI](https://pypi.org/project/SQLPyHelper/)
100
119
 
101
120
  For local development:
@@ -208,7 +227,9 @@ db.return_connection_to_pool(conn)
208
227
  | `return_connection_to_pool(conn)` | Returns connection back to pool. |
209
228
  | `begin_transaction()` | Begins an **explicit transaction**. |
210
229
  | `rollback_transaction()` | Rolls back **uncommitted transactions**. |
230
+ | `commit_transaction()` | Commits the current transaction. |
211
231
  | `close()` | Closes the database connection safely. |
232
+ | `__enter__` / `__exit__()` | Use as a context manager — connection closes automatically. |
212
233
 
213
234
  ---
214
235
  ## 🌍 Contributing
@@ -6,9 +6,17 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/adebayopeter/sqlpyhelper/blob/main/LICENSE)
7
7
  [![GitHub stars](https://img.shields.io/github/stars/adebayopeter/sqlpyhelper?style=social)](https://github.com/adebayopeter/sqlpyhelper)
8
8
 
9
- # 📌 SQLPyHelper v.0.1.4 🚀
9
+ SQLPyHelper is a lightweight Python library that gives you a single, consistent API across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** — without the overhead of an ORM.
10
10
 
11
- A Python library for simplified database interactions across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle**. SQLPyHelper provides an intuitive API for handling queries, connection pooling, transactions, logging, and backups efficiently.
11
+ If you need to run queries, manage transactions, pool connections, or back up tables across multiple database types without learning SQLAlchemy's abstraction layer or wiring up five different drivers manually, SQLPyHelper handles that boilerplate for you.
12
+
13
+ ```python
14
+ # Works identically across all five supported databases
15
+ with SQLPyHelper(db_type="postgres", host="localhost", user="user",
16
+ password="pass", database="mydb") as db:
17
+ db.execute_query("INSERT INTO orders (item) VALUES (%s)", ("Laptop",))
18
+ results = db.fetch_all()
19
+ ```
12
20
 
13
21
  ## 📖 Table of Contents
14
22
  - [🚀 Features](#-features)
@@ -27,7 +35,7 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
27
35
 
28
36
  ---
29
37
 
30
- ## 🚀 Features in v0.1.3
38
+ ## 🚀 Features in v0.1.4
31
39
  - Unified connection pooling for multiple databases.
32
40
  - Automatic reconnection for lost connections.
33
41
  - Transaction support (BEGIN, ROLLBACK, COMMIT).
@@ -38,10 +46,21 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
38
46
 
39
47
  ---
40
48
  ## 📦 Installation
41
- #### Install via PyPI:
49
+
50
+ Install the base package (includes SQLite support out of the box):
42
51
  ```sh
43
52
  pip install sqlpyhelper
44
53
  ```
54
+
55
+ Install with your database driver:
56
+ ```sh
57
+ pip install sqlpyhelper[postgres] # PostgreSQL
58
+ pip install sqlpyhelper[mysql] # MySQL
59
+ pip install sqlpyhelper[sqlserver] # SQL Server
60
+ pip install sqlpyhelper[oracle] # Oracle
61
+ pip install sqlpyhelper[all] # All databases
62
+ ```
63
+
45
64
  📌 Package on PyPI: [SQLPyHelper on PyPI](https://pypi.org/project/SQLPyHelper/)
46
65
 
47
66
  For local development:
@@ -154,7 +173,9 @@ db.return_connection_to_pool(conn)
154
173
  | `return_connection_to_pool(conn)` | Returns connection back to pool. |
155
174
  | `begin_transaction()` | Begins an **explicit transaction**. |
156
175
  | `rollback_transaction()` | Rolls back **uncommitted transactions**. |
176
+ | `commit_transaction()` | Commits the current transaction. |
157
177
  | `close()` | Closes the database connection safely. |
178
+ | `__enter__` / `__exit__()` | Use as a context manager — connection closes automatically. |
158
179
 
159
180
  ---
160
181
  ## 🌍 Contributing
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SQLPyHelper
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: A simple SQL database helper package for Python.
5
5
  Home-page: https://github.com/adebayopeter/sqlpyhelper
6
6
  Author: Adebayo Olaonipekun
@@ -32,12 +32,12 @@ Requires-Dist: mysql-connector-python; extra == "mysql"
32
32
  Provides-Extra: sqlserver
33
33
  Requires-Dist: pyodbc; extra == "sqlserver"
34
34
  Provides-Extra: oracle
35
- Requires-Dist: cx_Oracle; extra == "oracle"
35
+ Requires-Dist: oracledb; extra == "oracle"
36
36
  Provides-Extra: all
37
37
  Requires-Dist: psycopg2; extra == "all"
38
38
  Requires-Dist: mysql-connector-python; extra == "all"
39
39
  Requires-Dist: pyodbc; extra == "all"
40
- Requires-Dist: cx_Oracle; extra == "all"
40
+ Requires-Dist: oracledb; extra == "all"
41
41
  Dynamic: author
42
42
  Dynamic: author-email
43
43
  Dynamic: classifier
@@ -60,9 +60,17 @@ Dynamic: summary
60
60
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/adebayopeter/sqlpyhelper/blob/main/LICENSE)
61
61
  [![GitHub stars](https://img.shields.io/github/stars/adebayopeter/sqlpyhelper?style=social)](https://github.com/adebayopeter/sqlpyhelper)
62
62
 
63
- # 📌 SQLPyHelper v.0.1.4 🚀
63
+ SQLPyHelper is a lightweight Python library that gives you a single, consistent API across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** — without the overhead of an ORM.
64
64
 
65
- A Python library for simplified database interactions across **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle**. SQLPyHelper provides an intuitive API for handling queries, connection pooling, transactions, logging, and backups efficiently.
65
+ If you need to run queries, manage transactions, pool connections, or back up tables across multiple database types without learning SQLAlchemy's abstraction layer or wiring up five different drivers manually, SQLPyHelper handles that boilerplate for you.
66
+
67
+ ```python
68
+ # Works identically across all five supported databases
69
+ with SQLPyHelper(db_type="postgres", host="localhost", user="user",
70
+ password="pass", database="mydb") as db:
71
+ db.execute_query("INSERT INTO orders (item) VALUES (%s)", ("Laptop",))
72
+ results = db.fetch_all()
73
+ ```
66
74
 
67
75
  ## 📖 Table of Contents
68
76
  - [🚀 Features](#-features)
@@ -81,7 +89,7 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
81
89
 
82
90
  ---
83
91
 
84
- ## 🚀 Features in v0.1.3
92
+ ## 🚀 Features in v0.1.4
85
93
  - Unified connection pooling for multiple databases.
86
94
  - Automatic reconnection for lost connections.
87
95
  - Transaction support (BEGIN, ROLLBACK, COMMIT).
@@ -92,10 +100,21 @@ A Python library for simplified database interactions across **SQLite, PostgreSQ
92
100
 
93
101
  ---
94
102
  ## 📦 Installation
95
- #### Install via PyPI:
103
+
104
+ Install the base package (includes SQLite support out of the box):
96
105
  ```sh
97
106
  pip install sqlpyhelper
98
107
  ```
108
+
109
+ Install with your database driver:
110
+ ```sh
111
+ pip install sqlpyhelper[postgres] # PostgreSQL
112
+ pip install sqlpyhelper[mysql] # MySQL
113
+ pip install sqlpyhelper[sqlserver] # SQL Server
114
+ pip install sqlpyhelper[oracle] # Oracle
115
+ pip install sqlpyhelper[all] # All databases
116
+ ```
117
+
99
118
  📌 Package on PyPI: [SQLPyHelper on PyPI](https://pypi.org/project/SQLPyHelper/)
100
119
 
101
120
  For local development:
@@ -208,7 +227,9 @@ db.return_connection_to_pool(conn)
208
227
  | `return_connection_to_pool(conn)` | Returns connection back to pool. |
209
228
  | `begin_transaction()` | Begins an **explicit transaction**. |
210
229
  | `rollback_transaction()` | Rolls back **uncommitted transactions**. |
230
+ | `commit_transaction()` | Commits the current transaction. |
211
231
  | `close()` | Closes the database connection safely. |
232
+ | `__enter__` / `__exit__()` | Use as a context manager — connection closes automatically. |
212
233
 
213
234
  ---
214
235
  ## 🌍 Contributing
@@ -1,5 +1,7 @@
1
1
  LICENSE
2
2
  README.md
3
+ pyproject.toml
4
+ setup.cfg
3
5
  setup.py
4
6
  SQLPyHelper.egg-info/PKG-INFO
5
7
  SQLPyHelper.egg-info/SOURCES.txt
@@ -12,5 +14,4 @@ sqlpyhelper/automation_utils.py
12
14
  sqlpyhelper/cli.py
13
15
  sqlpyhelper/db_helper.py
14
16
  sqlpyhelper/py.typed
15
- test/test_automation.py
16
17
  test/test_sqlpyhelper.py
@@ -5,13 +5,13 @@ click
5
5
  psycopg2
6
6
  mysql-connector-python
7
7
  pyodbc
8
- cx_Oracle
8
+ oracledb
9
9
 
10
10
  [mysql]
11
11
  mysql-connector-python
12
12
 
13
13
  [oracle]
14
- cx_Oracle
14
+ oracledb
15
15
 
16
16
  [postgres]
17
17
  psycopg2
@@ -0,0 +1,6 @@
1
+ [tool.black]
2
+ line-length = 88
3
+
4
+ [tool.isort]
5
+ profile = "black"
6
+ line_length = 88
@@ -0,0 +1,21 @@
1
+ [flake8]
2
+ max-line-length = 120
3
+ ignore =
4
+ E203,
5
+ E501,
6
+ W503
7
+ exclude =
8
+ venv,
9
+ .git,
10
+ __pycache__,
11
+ dist,
12
+ build,
13
+ *.egg-info
14
+
15
+ [mypy]
16
+ ignore_missing_imports = True
17
+
18
+ [egg_info]
19
+ tag_build =
20
+ tag_date = 0
21
+
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as f:
5
5
 
6
6
  setup(
7
7
  name='SQLPyHelper',
8
- version='0.1.4',
8
+ version='0.1.5',
9
9
  description='A simple SQL database helper package for Python.',
10
10
  long_description=long_description,
11
11
  long_description_content_type="text/markdown",
@@ -25,12 +25,12 @@ setup(
25
25
  "postgres": ["psycopg2"],
26
26
  "mysql": ["mysql-connector-python"],
27
27
  "sqlserver": ["pyodbc"],
28
- "oracle": ["cx_Oracle"],
28
+ "oracle": ["oracledb"],
29
29
  "all": [
30
30
  "psycopg2",
31
31
  "mysql-connector-python",
32
32
  "pyodbc",
33
- "cx_Oracle",
33
+ "oracledb",
34
34
  ],
35
35
  },
36
36
  keywords=[
@@ -1,9 +1,9 @@
1
1
  # Match the version in setup.py
2
- __version__ = "0.1.4"
2
+ __version__ = "0.1.5"
3
3
 
4
- from sqlpyhelper.db_helper import (
5
- SQLPyHelperError,
4
+ from sqlpyhelper.db_helper import ( # noqa: F401
5
+ BackupError,
6
6
  ConnectionError,
7
7
  QueryError,
8
- BackupError,
8
+ SQLPyHelperError,
9
9
  )
@@ -1,9 +1,11 @@
1
- import pandas as pd
2
- from sqlpyhelper.db_helper import SQLPyHelper
3
- import subprocess
4
- from datetime import datetime
5
1
  import os
6
2
  import shutil
3
+ import subprocess
4
+ from datetime import datetime
5
+
6
+ import pandas as pd
7
+
8
+ from sqlpyhelper.db_helper import SQLPyHelper
7
9
 
8
10
 
9
11
  class AutomationUtils:
@@ -43,12 +45,17 @@ class AutomationUtils:
43
45
  subprocess.run(
44
46
  [
45
47
  "pg_dump",
46
- "-h", host,
47
- "-p", port,
48
- "-U", user,
48
+ "-h",
49
+ host,
50
+ "-p",
51
+ port,
52
+ "-U",
53
+ user,
49
54
  db_name,
50
- "-F", "c",
51
- "-f", filepath,
55
+ "-F",
56
+ "c",
57
+ "-f",
58
+ filepath,
52
59
  ],
53
60
  check=True,
54
61
  shell=False,
@@ -82,7 +89,7 @@ class AutomationUtils:
82
89
  entity_column (str): Column representing entity ID.
83
90
  date_column (str): Column representing timestamp/date.
84
91
  """
85
- if self.db.db_type == 'sqlite':
92
+ if self.db.db_type == "sqlite":
86
93
  month_expr = f"strftime('%Y-%m', {date_column})"
87
94
  else:
88
95
  month_expr = f"DATE_TRUNC('month', {date_column})"
@@ -95,7 +102,9 @@ class AutomationUtils:
95
102
  self.db.execute_query(query)
96
103
  return self.db.fetch_all()
97
104
 
98
- def aggregate_column(self, table, value_column, group_column=None, time_column=None):
105
+ def aggregate_column(
106
+ self, table, value_column, group_column=None, time_column=None
107
+ ):
99
108
  """
100
109
  Computes sum of any value column grouped by entity or month.
101
110
 
@@ -105,7 +114,7 @@ class AutomationUtils:
105
114
  group_column (str, optional): Entity or category to group by.
106
115
  time_column (str, optional): Timestamp to extract month grouping.
107
116
  """
108
- if self.db.db_type == 'sqlite':
117
+ if self.db.db_type == "sqlite":
109
118
  month_expr = f"strftime('%Y-%m', {time_column})"
110
119
  else:
111
120
  month_expr = f"DATE_TRUNC('month', {time_column})"
@@ -133,11 +142,13 @@ class AutomationUtils:
133
142
  threshold (int): Number of standard deviations from mean to flag as outlier.
134
143
  """
135
144
  query = f"""
136
- SELECT *, {numeric_column}
137
- AS value FROM {table}
145
+ SELECT *, {numeric_column} AS value FROM {table}
138
146
  """
139
147
  self.db.execute_query(query)
140
- data = pd.DataFrame(self.db.fetch_all(), columns=[desc[0] for desc in self.db.cursor.description])
148
+ data = pd.DataFrame(
149
+ self.db.fetch_all(),
150
+ columns=[desc[0] for desc in self.db.cursor.description],
151
+ )
141
152
 
142
153
  mean_val = data["value"].mean()
143
154
  std_val = data["value"].std()
@@ -0,0 +1,199 @@
1
+ import click
2
+
3
+ from sqlpyhelper.automation_utils import AutomationUtils
4
+ from sqlpyhelper.db_helper import SQLPyHelper
5
+
6
+
7
+ @click.group()
8
+ def cli():
9
+ """SQLPyHelper Command Line Interface"""
10
+ pass
11
+
12
+
13
+ @cli.command()
14
+ @click.option("--db_type", help="Type of database (e.g., sqlite, postgres, mysql)")
15
+ @click.option("--host", help="Database host")
16
+ @click.option("--user", help="Username")
17
+ @click.option("--password", help="Password")
18
+ @click.option("--database", help="Database name or file")
19
+ @click.option("--query", required=True, help="SQL query to run")
20
+ def run_query(db_type, host, user, password, database, query):
21
+ """Run a single SQL query and print results"""
22
+ db = SQLPyHelper(
23
+ db_type=db_type, host=host, user=user, password=password, database=database
24
+ )
25
+ results = db.execute_query(query)
26
+ for row in results:
27
+ click.echo(row)
28
+ db.close()
29
+
30
+
31
+ @cli.command()
32
+ @click.option("--db_type", required=True)
33
+ @click.option("--host")
34
+ @click.option("--user")
35
+ @click.option("--password")
36
+ @click.option("--database", required=True)
37
+ def interactive_shell(db_type, host, user, password, database):
38
+ """Launch an interactive SQL shell"""
39
+ db = SQLPyHelper(
40
+ db_type=db_type, host=host, user=user, password=password, database=database
41
+ )
42
+ click.echo("Interactive shell started. Type your SQL query or 'exit'")
43
+ while True:
44
+ query = input("sqlpy> ")
45
+ if query.lower() in ("exit", "quit"):
46
+ break
47
+ try:
48
+ db.execute_query(query)
49
+ results = db.fetch_all()
50
+ for row in results:
51
+ click.echo(row)
52
+ except Exception as e:
53
+ click.echo(f"Error: {e}")
54
+ db.close()
55
+
56
+
57
+ @cli.command()
58
+ @click.option("--target", default="local", help="Backup destination")
59
+ @click.option("--tag", default="autobackup", help="Tag for backup file naming")
60
+ @click.option("--db-type")
61
+ @click.option("--host")
62
+ @click.option("--user")
63
+ @click.option("--password")
64
+ @click.option("--database")
65
+ @click.option("--port")
66
+ def backup(target, tag, db_type, host, user, password, database, port):
67
+ """Create a timestamped backup of the connected database."""
68
+ utils = AutomationUtils(
69
+ db_type=db_type,
70
+ host=host,
71
+ user=user,
72
+ password=password,
73
+ database=database,
74
+ port=port,
75
+ )
76
+ utils.backup_database(target=target, tag=tag)
77
+
78
+
79
+ @cli.command()
80
+ @click.option("--file", required=True, help="Path to CSV file")
81
+ @click.option("--table", required=True, help="Destination table")
82
+ @click.option(
83
+ "--if-exists",
84
+ default="append",
85
+ type=click.Choice(["append", "replace"]),
86
+ help="What to do if table exists",
87
+ )
88
+ @click.option("--db-type")
89
+ @click.option("--host")
90
+ @click.option("--user")
91
+ @click.option("--password")
92
+ @click.option("--database")
93
+ @click.option("--port")
94
+ def load_data(file, table, if_exists, db_type, host, user, password, database, port):
95
+ """Load data from CSV into database table."""
96
+ utils = AutomationUtils(
97
+ db_type=db_type,
98
+ host=host,
99
+ user=user,
100
+ password=password,
101
+ database=database,
102
+ port=port,
103
+ )
104
+ utils.load_data_from_csv(file, table, if_exists=if_exists)
105
+
106
+
107
+ @cli.command()
108
+ @click.option("--table", required=True)
109
+ @click.option("--entity-column", required=True)
110
+ @click.option("--date-column", required=True)
111
+ @click.option("--db-type")
112
+ @click.option("--host")
113
+ @click.option("--user")
114
+ @click.option("--password")
115
+ @click.option("--database")
116
+ @click.option("--port")
117
+ def detect_missing_periods(
118
+ table, entity_column, date_column, db_type, host, user, password, database, port
119
+ ):
120
+ """Flag entities with fewer than 12 months of activity."""
121
+ utils = AutomationUtils(
122
+ db_type=db_type,
123
+ host=host,
124
+ user=user,
125
+ password=password,
126
+ database=database,
127
+ port=port,
128
+ )
129
+ results = utils.detect_missing_periods(table, entity_column, date_column)
130
+ for row in results:
131
+ click.echo(row)
132
+
133
+
134
+ @cli.command()
135
+ @click.option("--table", required=True)
136
+ @click.option("--value-column", required=True)
137
+ @click.option("--group-column")
138
+ @click.option("--time-column")
139
+ @click.option("--db-type")
140
+ @click.option("--host")
141
+ @click.option("--user")
142
+ @click.option("--password")
143
+ @click.option("--database")
144
+ @click.option("--port")
145
+ def aggregate(
146
+ table,
147
+ value_column,
148
+ group_column,
149
+ time_column,
150
+ db_type,
151
+ host,
152
+ user,
153
+ password,
154
+ database,
155
+ port,
156
+ ):
157
+ """Aggregate numeric column optionally grouped by entity and time."""
158
+ utils = AutomationUtils(
159
+ db_type=db_type,
160
+ host=host,
161
+ user=user,
162
+ password=password,
163
+ database=database,
164
+ port=port,
165
+ )
166
+ results = utils.aggregate_column(table, value_column, group_column, time_column)
167
+ for row in results:
168
+ click.echo(row)
169
+
170
+
171
+ @cli.command()
172
+ @click.option("--table", required=True)
173
+ @click.option("--numeric-column", required=True)
174
+ @click.option("--threshold", default=2, type=int)
175
+ @click.option("--db-type")
176
+ @click.option("--host")
177
+ @click.option("--user")
178
+ @click.option("--password")
179
+ @click.option("--database")
180
+ @click.option("--port")
181
+ def detect_outliers(
182
+ table, numeric_column, threshold, db_type, host, user, password, database, port
183
+ ):
184
+ """Flag rows where values deviate statistically from average."""
185
+ utils = AutomationUtils(
186
+ db_type=db_type,
187
+ host=host,
188
+ user=user,
189
+ password=password,
190
+ database=database,
191
+ port=port,
192
+ )
193
+ results = utils.detect_outliers(table, numeric_column, threshold)
194
+ for row in results:
195
+ click.echo(row)
196
+
197
+
198
+ if __name__ == "__main__":
199
+ cli()