dynamic-tables 0.1.0__tar.gz → 0.2.0__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.
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/PKG-INFO +47 -20
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/README.md +45 -17
- dynamic_tables-0.2.0/dynamic_tables/dynamic_tables.py +336 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables.egg-info/PKG-INFO +47 -20
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/setup.py +2 -5
- dynamic_tables-0.1.0/dynamic_tables/dynamic_tables.py +0 -224
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables/__init__.py +0 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables.egg-info/SOURCES.txt +0 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables.egg-info/dependency_links.txt +0 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables.egg-info/requires.txt +0 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/dynamic_tables.egg-info/top_level.txt +0 -0
- {dynamic_tables-0.1.0 → dynamic_tables-0.2.0}/setup.cfg +0 -0
@@ -1,15 +1,17 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dynamic_tables
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: A dynamic table creation and management library for PostgreSQL
|
5
|
-
Home-page: https://github.com/scottrodeo/
|
5
|
+
Home-page: https://github.com/scottrodeo/dynamic-tables-python
|
6
6
|
Author: Scott Rodeo
|
7
7
|
Author-email: signcactus@gmail.com
|
8
8
|
License: UNKNOWN
|
9
|
-
Project-URL: Author Website, https://patreon.com/scottrodeo
|
10
9
|
Description: # Dynamic Tables (Python)
|
10
|
+
|
11
11
|
A Python library for dynamically creating and managing PostgreSQL tables based on input data.
|
12
12
|
|
13
|
+
---
|
14
|
+
|
13
15
|
## 🚀 Features
|
14
16
|
- Automatically creates tables based on incoming data.
|
15
17
|
- Supports dynamic naming conventions.
|
@@ -19,16 +21,19 @@ Description: # Dynamic Tables (Python)
|
|
19
21
|
---
|
20
22
|
|
21
23
|
## 📥 Installation
|
22
|
-
|
24
|
+
|
25
|
+
### 1️⃣ Install via GitHub (Recommended for Development)
|
23
26
|
Clone the repository and install in editable mode:
|
27
|
+
|
24
28
|
```bash
|
25
29
|
git clone https://github.com/scottrodeo/dynamic-tables-python.git
|
26
30
|
cd dynamic-tables-python
|
27
31
|
pip install -e .
|
28
32
|
```
|
29
33
|
|
30
|
-
###
|
31
|
-
The package is available on PyPI,
|
34
|
+
### 2️⃣ Install Directly via `pip`
|
35
|
+
The package is available on PyPI, install it with:
|
36
|
+
|
32
37
|
```bash
|
33
38
|
pip install dynamic-tables
|
34
39
|
```
|
@@ -36,22 +41,21 @@ Description: # Dynamic Tables (Python)
|
|
36
41
|
---
|
37
42
|
|
38
43
|
## 🏃♂️ Running the Example
|
39
|
-
|
40
|
-
|
44
|
+
|
45
|
+
### 1️⃣ Quick Run (Without Installation)
|
46
|
+
Run the example script directly:
|
47
|
+
|
41
48
|
```bash
|
42
49
|
python3 examples/example.py
|
43
50
|
```
|
51
|
+
|
44
52
|
💡 *This works because the script dynamically adjusts `sys.path`.*
|
45
53
|
|
46
|
-
### **2️⃣ Recommended (After Installation)**
|
47
|
-
If you've installed the package (`pip install -e .`), simply run:
|
48
|
-
```bash
|
49
|
-
python3 examples/example.py
|
50
|
-
```
|
51
54
|
|
52
55
|
---
|
53
56
|
|
54
57
|
## 📌 Example Usage
|
58
|
+
|
55
59
|
Once installed, you can use `dynamic_tables` in your Python scripts:
|
56
60
|
|
57
61
|
```python
|
@@ -60,11 +64,12 @@ Description: # Dynamic Tables (Python)
|
|
60
64
|
# Initialize the dynamic table manager
|
61
65
|
tables = DynamicTables()
|
62
66
|
|
63
|
-
#
|
67
|
+
# Configure dynamic table properties
|
64
68
|
tables.set_table_prefix("dtbl_")
|
65
69
|
tables.set_columns("domain TEXT, category TEXT, lang TEXT")
|
66
70
|
tables.set_dynamic_column("domain")
|
67
71
|
|
72
|
+
# Insert dynamic data
|
68
73
|
tables.input("wikipedia.org", "cats", "en")
|
69
74
|
tables.input("wikipedia.org", "dogs", "en")
|
70
75
|
|
@@ -75,6 +80,7 @@ Description: # Dynamic Tables (Python)
|
|
75
80
|
---
|
76
81
|
|
77
82
|
## 🛠️ Available Functions
|
83
|
+
|
78
84
|
| Function | Description |
|
79
85
|
|----------|-------------|
|
80
86
|
| `set_columns("name TYPE, age TYPE")` | Define table schema |
|
@@ -83,20 +89,39 @@ Description: # Dynamic Tables (Python)
|
|
83
89
|
| `input(value1, value2, ...)` | Insert a new row dynamically |
|
84
90
|
| `show_tables()` | List all dynamically created tables |
|
85
91
|
| `show_columns("table_name")` | Show column details for a specific table |
|
92
|
+
| `show_columns_all()` | Show column details for all tables |
|
86
93
|
| `select_table("table_name")` | Retrieve all rows from a table |
|
87
94
|
| `delete_tables()` | Drop all tables matching the prefix |
|
95
|
+
| `create_table("table_name", [("column1", "TYPE"), ("column2", "TYPE")])` | Create a table dynamically |
|
96
|
+
| `insert_data("table_name", {"column1": value1, "column2": value2})` | Insert data into a specific table |
|
97
|
+
| `get_tables()` | Retrieve a list of all tables in the database |
|
98
|
+
| `get_columns("table_name")` | Retrieve all columns for a given table |
|
99
|
+
| `get_table_rows("table_name")` | Retrieve all rows from a table |
|
100
|
+
| `connectHC("dbname", "user", "password", "host")` | Connect using hardcoded credentials |
|
101
|
+
| `connectJSON("config.json")` | Connect using credentials from a JSON config file |
|
102
|
+
| `connectENVS()` | Connect using environment variables |
|
103
|
+
| `connection_open("dbname", "user", "password", "host")` | Open a PostgreSQL database connection |
|
104
|
+
| `connection_close()` | Close the database connection |
|
105
|
+
| `status()` | Show the current configuration status |
|
106
|
+
| `show_db()` | Display the connected database name |
|
107
|
+
| `setup_logging(level, log_to_file)` | Configure logging settings |
|
108
|
+
| `change_log_level("LEVEL")` | Change the logging level at runtime |
|
109
|
+
| `show_version()` | Display the current version of the library |
|
88
110
|
|
89
111
|
---
|
90
112
|
|
91
113
|
## ⚡ Development
|
92
|
-
|
93
|
-
|
114
|
+
|
115
|
+
### Running Tests
|
116
|
+
Run the test suite:
|
117
|
+
|
94
118
|
```bash
|
95
119
|
pytest tests/
|
96
120
|
```
|
97
121
|
|
98
|
-
###
|
122
|
+
### Linting
|
99
123
|
Ensure your code follows best practices:
|
124
|
+
|
100
125
|
```bash
|
101
126
|
flake8 dynamic_tables/
|
102
127
|
```
|
@@ -104,7 +129,8 @@ Description: # Dynamic Tables (Python)
|
|
104
129
|
---
|
105
130
|
|
106
131
|
## 🤝 Contributing
|
107
|
-
|
132
|
+
|
133
|
+
Contributions are welcome! To contribute:
|
108
134
|
1. Fork the repository.
|
109
135
|
2. Create a new branch (`git checkout -b feature-branch`).
|
110
136
|
3. Commit your changes (`git commit -m "Added new feature"`).
|
@@ -114,18 +140,19 @@ Description: # Dynamic Tables (Python)
|
|
114
140
|
---
|
115
141
|
|
116
142
|
## 📄 License
|
143
|
+
|
117
144
|
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
118
145
|
|
119
146
|
---
|
120
147
|
|
121
148
|
## 🌎 Links
|
149
|
+
|
122
150
|
- **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
|
123
|
-
- **Documentation:** *(To be added)*
|
124
151
|
- **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
|
125
152
|
|
126
153
|
---
|
127
154
|
|
128
|
-
###
|
155
|
+
### 🚀 Happy Coding!
|
129
156
|
|
130
157
|
|
131
158
|
Platform: UNKNOWN
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# Dynamic Tables (Python)
|
2
|
+
|
2
3
|
A Python library for dynamically creating and managing PostgreSQL tables based on input data.
|
3
4
|
|
5
|
+
---
|
6
|
+
|
4
7
|
## 🚀 Features
|
5
8
|
- Automatically creates tables based on incoming data.
|
6
9
|
- Supports dynamic naming conventions.
|
@@ -10,16 +13,19 @@ A Python library for dynamically creating and managing PostgreSQL tables based o
|
|
10
13
|
---
|
11
14
|
|
12
15
|
## 📥 Installation
|
13
|
-
|
16
|
+
|
17
|
+
### 1️⃣ Install via GitHub (Recommended for Development)
|
14
18
|
Clone the repository and install in editable mode:
|
19
|
+
|
15
20
|
```bash
|
16
21
|
git clone https://github.com/scottrodeo/dynamic-tables-python.git
|
17
22
|
cd dynamic-tables-python
|
18
23
|
pip install -e .
|
19
24
|
```
|
20
25
|
|
21
|
-
###
|
22
|
-
The package is available on PyPI,
|
26
|
+
### 2️⃣ Install Directly via `pip`
|
27
|
+
The package is available on PyPI, install it with:
|
28
|
+
|
23
29
|
```bash
|
24
30
|
pip install dynamic-tables
|
25
31
|
```
|
@@ -27,22 +33,21 @@ pip install dynamic-tables
|
|
27
33
|
---
|
28
34
|
|
29
35
|
## 🏃♂️ Running the Example
|
30
|
-
|
31
|
-
|
36
|
+
|
37
|
+
### 1️⃣ Quick Run (Without Installation)
|
38
|
+
Run the example script directly:
|
39
|
+
|
32
40
|
```bash
|
33
41
|
python3 examples/example.py
|
34
42
|
```
|
43
|
+
|
35
44
|
💡 *This works because the script dynamically adjusts `sys.path`.*
|
36
45
|
|
37
|
-
### **2️⃣ Recommended (After Installation)**
|
38
|
-
If you've installed the package (`pip install -e .`), simply run:
|
39
|
-
```bash
|
40
|
-
python3 examples/example.py
|
41
|
-
```
|
42
46
|
|
43
47
|
---
|
44
48
|
|
45
49
|
## 📌 Example Usage
|
50
|
+
|
46
51
|
Once installed, you can use `dynamic_tables` in your Python scripts:
|
47
52
|
|
48
53
|
```python
|
@@ -51,11 +56,12 @@ from dynamic_tables import DynamicTables
|
|
51
56
|
# Initialize the dynamic table manager
|
52
57
|
tables = DynamicTables()
|
53
58
|
|
54
|
-
#
|
59
|
+
# Configure dynamic table properties
|
55
60
|
tables.set_table_prefix("dtbl_")
|
56
61
|
tables.set_columns("domain TEXT, category TEXT, lang TEXT")
|
57
62
|
tables.set_dynamic_column("domain")
|
58
63
|
|
64
|
+
# Insert dynamic data
|
59
65
|
tables.input("wikipedia.org", "cats", "en")
|
60
66
|
tables.input("wikipedia.org", "dogs", "en")
|
61
67
|
|
@@ -66,6 +72,7 @@ tables.show_tables()
|
|
66
72
|
---
|
67
73
|
|
68
74
|
## 🛠️ Available Functions
|
75
|
+
|
69
76
|
| Function | Description |
|
70
77
|
|----------|-------------|
|
71
78
|
| `set_columns("name TYPE, age TYPE")` | Define table schema |
|
@@ -74,20 +81,39 @@ tables.show_tables()
|
|
74
81
|
| `input(value1, value2, ...)` | Insert a new row dynamically |
|
75
82
|
| `show_tables()` | List all dynamically created tables |
|
76
83
|
| `show_columns("table_name")` | Show column details for a specific table |
|
84
|
+
| `show_columns_all()` | Show column details for all tables |
|
77
85
|
| `select_table("table_name")` | Retrieve all rows from a table |
|
78
86
|
| `delete_tables()` | Drop all tables matching the prefix |
|
87
|
+
| `create_table("table_name", [("column1", "TYPE"), ("column2", "TYPE")])` | Create a table dynamically |
|
88
|
+
| `insert_data("table_name", {"column1": value1, "column2": value2})` | Insert data into a specific table |
|
89
|
+
| `get_tables()` | Retrieve a list of all tables in the database |
|
90
|
+
| `get_columns("table_name")` | Retrieve all columns for a given table |
|
91
|
+
| `get_table_rows("table_name")` | Retrieve all rows from a table |
|
92
|
+
| `connectHC("dbname", "user", "password", "host")` | Connect using hardcoded credentials |
|
93
|
+
| `connectJSON("config.json")` | Connect using credentials from a JSON config file |
|
94
|
+
| `connectENVS()` | Connect using environment variables |
|
95
|
+
| `connection_open("dbname", "user", "password", "host")` | Open a PostgreSQL database connection |
|
96
|
+
| `connection_close()` | Close the database connection |
|
97
|
+
| `status()` | Show the current configuration status |
|
98
|
+
| `show_db()` | Display the connected database name |
|
99
|
+
| `setup_logging(level, log_to_file)` | Configure logging settings |
|
100
|
+
| `change_log_level("LEVEL")` | Change the logging level at runtime |
|
101
|
+
| `show_version()` | Display the current version of the library |
|
79
102
|
|
80
103
|
---
|
81
104
|
|
82
105
|
## ⚡ Development
|
83
|
-
|
84
|
-
|
106
|
+
|
107
|
+
### Running Tests
|
108
|
+
Run the test suite:
|
109
|
+
|
85
110
|
```bash
|
86
111
|
pytest tests/
|
87
112
|
```
|
88
113
|
|
89
|
-
###
|
114
|
+
### Linting
|
90
115
|
Ensure your code follows best practices:
|
116
|
+
|
91
117
|
```bash
|
92
118
|
flake8 dynamic_tables/
|
93
119
|
```
|
@@ -95,7 +121,8 @@ flake8 dynamic_tables/
|
|
95
121
|
---
|
96
122
|
|
97
123
|
## 🤝 Contributing
|
98
|
-
|
124
|
+
|
125
|
+
Contributions are welcome! To contribute:
|
99
126
|
1. Fork the repository.
|
100
127
|
2. Create a new branch (`git checkout -b feature-branch`).
|
101
128
|
3. Commit your changes (`git commit -m "Added new feature"`).
|
@@ -105,16 +132,17 @@ Contributions are welcome! If you'd like to improve `dynamic_tables`, follow the
|
|
105
132
|
---
|
106
133
|
|
107
134
|
## 📄 License
|
135
|
+
|
108
136
|
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
109
137
|
|
110
138
|
---
|
111
139
|
|
112
140
|
## 🌎 Links
|
141
|
+
|
113
142
|
- **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
|
114
|
-
- **Documentation:** *(To be added)*
|
115
143
|
- **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
|
116
144
|
|
117
145
|
---
|
118
146
|
|
119
|
-
###
|
147
|
+
### 🚀 Happy Coding!
|
120
148
|
|
@@ -0,0 +1,336 @@
|
|
1
|
+
# this is dynamic_tables.py
|
2
|
+
|
3
|
+
import psycopg2, re, logging
|
4
|
+
from psycopg2 import sql
|
5
|
+
|
6
|
+
class DynamicTables:
|
7
|
+
|
8
|
+
def __init__(self):
|
9
|
+
"""Initialize the class by calling self.initialize() to set up default values."""
|
10
|
+
self.initialize()
|
11
|
+
|
12
|
+
def initialize(self):
|
13
|
+
"""Sets up default attributes for the table structure."""
|
14
|
+
self.column_list = []
|
15
|
+
self.column_dynamic = ''
|
16
|
+
self.table_prefix = 'dtbl_'
|
17
|
+
self.table_name_dynamic = ''
|
18
|
+
self.version = '0.1.2'
|
19
|
+
"""Initialize with default logging level (CRITICAL) and no file logging."""
|
20
|
+
self.log_file_handler = None
|
21
|
+
self.setup_logging(level=logging.CRITICAL, log_to_file=False)
|
22
|
+
|
23
|
+
def setup_logging(self, level=logging.CRITICAL, log_to_file=False):
|
24
|
+
"""
|
25
|
+
Configures logging level and optionally enables file logging.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
level (int): Logging level (e.g., logging.DEBUG, logging.INFO).
|
29
|
+
log_to_file (bool): Enable or disable file logging.
|
30
|
+
"""
|
31
|
+
logging.basicConfig(
|
32
|
+
level=level,
|
33
|
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
34
|
+
handlers=[logging.StreamHandler()] # Console only by default
|
35
|
+
)
|
36
|
+
|
37
|
+
# Enable file logging if requested
|
38
|
+
if log_to_file and not self.log_file_handler:
|
39
|
+
self.log_file_handler = logging.FileHandler("dynamic_tables.log")
|
40
|
+
self.log_file_handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
|
41
|
+
logging.getLogger().addHandler(self.log_file_handler)
|
42
|
+
|
43
|
+
# Disable file logging if requested
|
44
|
+
elif not log_to_file and self.log_file_handler:
|
45
|
+
logging.getLogger().removeHandler(self.log_file_handler)
|
46
|
+
self.log_file_handler.close()
|
47
|
+
self.log_file_handler = None
|
48
|
+
|
49
|
+
logging.info(f"Logging level set to {logging.getLevelName(level)}")
|
50
|
+
if log_to_file:
|
51
|
+
logging.info("File logging enabled (dynamic_tables.log)")
|
52
|
+
|
53
|
+
def change_log_level(self, level_name):
|
54
|
+
"""
|
55
|
+
Change the logging level at runtime.
|
56
|
+
Args:
|
57
|
+
level_name (str): "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
|
58
|
+
"""
|
59
|
+
level = getattr(logging, level_name.upper(), logging.CRITICAL)
|
60
|
+
logging.getLogger().setLevel(level)
|
61
|
+
logging.info(f"Log level changed to {level_name.upper()}")
|
62
|
+
|
63
|
+
def set_columns(self, input_columns):
|
64
|
+
"""Sets the columns for table creation based on user input."""
|
65
|
+
self.column_list = []
|
66
|
+
for column in input_columns.split(','):
|
67
|
+
column = column.strip()
|
68
|
+
parts = column.split(maxsplit=1)
|
69
|
+
if len(parts) == 2:
|
70
|
+
self.column_list.append((parts[0], parts[1]))
|
71
|
+
else:
|
72
|
+
logging.warning(f"Invalid column format: '{column}'")
|
73
|
+
|
74
|
+
def set_table_prefix(self, input_prefix):
|
75
|
+
"""Defines a custom table name prefix."""
|
76
|
+
self.table_prefix = input_prefix
|
77
|
+
|
78
|
+
def set_dynamic_column(self, input_column):
|
79
|
+
"""Sets the column that determines dynamic table names."""
|
80
|
+
self.column_dynamic = input_column
|
81
|
+
|
82
|
+
def connection_open(self, dbname, user, password, host):
|
83
|
+
"""Opens a connection to the PostgreSQL database and initializes the cursor."""
|
84
|
+
self.conn = psycopg2.connect(
|
85
|
+
dbname=dbname,
|
86
|
+
user=user,
|
87
|
+
password=password,
|
88
|
+
host=host
|
89
|
+
)
|
90
|
+
self.cur = self.conn.cursor()
|
91
|
+
|
92
|
+
def connectHC(self, database, user, password, host):
|
93
|
+
"""Helper function to open a connection using hardcoded credentials."""
|
94
|
+
self.connection_open(database, user, password, host)
|
95
|
+
|
96
|
+
def connectJSON(self, config_path="config.json"):
|
97
|
+
"""Opens a database connection using credentials from a JSON config file."""
|
98
|
+
import json
|
99
|
+
with open(config_path) as config_file:
|
100
|
+
config = json.load(config_file)
|
101
|
+
database=config["database"]
|
102
|
+
user=config["user"]
|
103
|
+
password=config["password"]
|
104
|
+
host=config["host"]
|
105
|
+
self.connection_open(database, user, password, host)
|
106
|
+
|
107
|
+
def connectENVS(self):
|
108
|
+
"""Opens a database connection using environment variables."""
|
109
|
+
import os
|
110
|
+
database=os.getenv("DTABLES_ENVS_PGSQL_DATABASE")
|
111
|
+
user=os.getenv("DTABLES_ENVS_PGSQL_USER")
|
112
|
+
password=os.getenv("DTABLES_ENVS_PGSQL_PASSWORD")
|
113
|
+
host=os.getenv("DTABLES_ENVS_PGSQL_HOST")
|
114
|
+
self.connection_open(database, user, password, host)
|
115
|
+
|
116
|
+
def connection_close(self):
|
117
|
+
"""Closes the database cursor and connection."""
|
118
|
+
self.cur.close()
|
119
|
+
self.conn.close()
|
120
|
+
|
121
|
+
def close(self):
|
122
|
+
"""Alias for connection_close() to improve readability."""
|
123
|
+
self.connection_close()
|
124
|
+
|
125
|
+
def get_tables(self):
|
126
|
+
"""Returns a list of all table names in the public schema."""
|
127
|
+
try:
|
128
|
+
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
129
|
+
tables = self.cur.fetchall()
|
130
|
+
|
131
|
+
if tables:
|
132
|
+
table_list = [table[0] for table in tables] # Convert to a simple list of table names
|
133
|
+
logging.info(f"Found {len(table_list)} tables.")
|
134
|
+
logging.debug(f"Tables: {table_list}")
|
135
|
+
return table_list
|
136
|
+
else:
|
137
|
+
logging.info("No tables found.")
|
138
|
+
return [] # Empty list instead of None for consistency
|
139
|
+
|
140
|
+
except Exception as e:
|
141
|
+
logging.error(f"Error retrieving tables: {e}", exc_info=True)
|
142
|
+
return None
|
143
|
+
|
144
|
+
def get_columns(self, table_name):
|
145
|
+
"""Returns a list of all columns and their data types for a given table."""
|
146
|
+
try:
|
147
|
+
query = sql.SQL("""
|
148
|
+
SELECT column_name, data_type
|
149
|
+
FROM information_schema.columns
|
150
|
+
WHERE table_name = %s
|
151
|
+
ORDER BY ordinal_position;
|
152
|
+
""")
|
153
|
+
self.cur.execute(query, (table_name,))
|
154
|
+
columns = self.cur.fetchall()
|
155
|
+
|
156
|
+
if columns:
|
157
|
+
logging.info(f"Retrieved {len(columns)} columns from '{table_name}'.")
|
158
|
+
return columns
|
159
|
+
else:
|
160
|
+
logging.warning(f"No columns found for table '{table_name}' or the table does not exist.")
|
161
|
+
return []
|
162
|
+
|
163
|
+
except Exception as e:
|
164
|
+
logging.error(f"Error retrieving columns for '{table_name}': {e}", exc_info=True)
|
165
|
+
return None
|
166
|
+
|
167
|
+
def get_table_rows(self, table_name):
|
168
|
+
"""Retrieves all rows from the specified table and returns them."""
|
169
|
+
try:
|
170
|
+
query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name))
|
171
|
+
self.cur.execute(query)
|
172
|
+
rows = self.cur.fetchall()
|
173
|
+
|
174
|
+
if rows:
|
175
|
+
logging.info(f"Retrieved {len(rows)} rows from '{table_name}'.")
|
176
|
+
logging.debug(f"Rows from '{table_name}': {rows}")
|
177
|
+
return rows # Returns data for other functions
|
178
|
+
else:
|
179
|
+
logging.info(f"Table '{table_name}' exists but has no data.")
|
180
|
+
return []
|
181
|
+
|
182
|
+
except Exception as e:
|
183
|
+
logging.error(f"Error retrieving rows from '{table_name}': {e}", exc_info=True)
|
184
|
+
return None
|
185
|
+
|
186
|
+
def show_db(self):
|
187
|
+
"""Displays the name of the current database."""
|
188
|
+
self.cur.execute("SELECT current_database();")
|
189
|
+
db_name = self.cur.fetchone()[0]
|
190
|
+
logging.info(f"Connected to database: {db_name}")
|
191
|
+
|
192
|
+
def show_tables(self):
|
193
|
+
"""Prints a list of all table names (uses get_tables)."""
|
194
|
+
tables = self.get_tables()
|
195
|
+
|
196
|
+
if tables:
|
197
|
+
print("Tables in the database:")
|
198
|
+
for table in tables:
|
199
|
+
print(f" - {table}")
|
200
|
+
else:
|
201
|
+
print("No tables found or an error occurred.")
|
202
|
+
|
203
|
+
def show_columns(self, table_name):
|
204
|
+
"""Prints column details for human readability (uses get_columns)."""
|
205
|
+
columns = self.get_columns(table_name)
|
206
|
+
|
207
|
+
if columns:
|
208
|
+
print(f"Columns in '{table_name}':")
|
209
|
+
for name, dtype in columns:
|
210
|
+
print(f" - {name}: {dtype}")
|
211
|
+
else:
|
212
|
+
print(f"No columns found for '{table_name}' or the table does not exist.")
|
213
|
+
|
214
|
+
def show_columns_all(self):
|
215
|
+
"""Lists column details for all tables."""
|
216
|
+
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
217
|
+
for table in self.cur.fetchall():
|
218
|
+
self.show_columns(table[0])
|
219
|
+
|
220
|
+
def show_table(self, table_name):
|
221
|
+
"""Displays all rows from the specified table (uses get_table_rows)."""
|
222
|
+
rows = self.get_table_rows(table_name)
|
223
|
+
|
224
|
+
if rows:
|
225
|
+
print(f"Rows in '{table_name}':")
|
226
|
+
for row in rows:
|
227
|
+
print(f" - {row}")
|
228
|
+
else:
|
229
|
+
print(f"Table '{table_name}' exists but has no data or an error occurred.")
|
230
|
+
|
231
|
+
def show_version(self):
|
232
|
+
"""Show the current software version"""
|
233
|
+
print(self.version)
|
234
|
+
|
235
|
+
def select_table(self, table_name):
|
236
|
+
"""Retrieves and prints all rows from the specified table."""
|
237
|
+
self.show_table(table_name)
|
238
|
+
|
239
|
+
def insert_data(self, table_name, data_dict):
|
240
|
+
"""Inserts data into a dynamically created table."""
|
241
|
+
columns = data_dict.keys()
|
242
|
+
values = list(data_dict.values())
|
243
|
+
|
244
|
+
query = sql.SQL("""
|
245
|
+
INSERT INTO {} ({})
|
246
|
+
VALUES ({});
|
247
|
+
""").format(
|
248
|
+
sql.Identifier(table_name),
|
249
|
+
sql.SQL(', ').join(map(sql.Identifier, columns)),
|
250
|
+
sql.SQL(', ').join(sql.Placeholder() for _ in columns)
|
251
|
+
)
|
252
|
+
|
253
|
+
self.cur.execute(query, values)
|
254
|
+
self.conn.commit()
|
255
|
+
|
256
|
+
def create_table(self, table_name, columns):
|
257
|
+
"""Creates a table dynamically if it does not already exist."""
|
258
|
+
column_definitions = sql.SQL(", ").join(
|
259
|
+
sql.SQL("{} {}").format(sql.Identifier(col_name), sql.SQL(col_type))
|
260
|
+
for col_name, col_type in columns
|
261
|
+
)
|
262
|
+
|
263
|
+
query = sql.SQL("""
|
264
|
+
CREATE TABLE IF NOT EXISTS {} (
|
265
|
+
id SERIAL PRIMARY KEY,
|
266
|
+
{}
|
267
|
+
);
|
268
|
+
""").format(sql.Identifier(table_name), column_definitions)
|
269
|
+
|
270
|
+
self.cur.execute(query)
|
271
|
+
self.conn.commit()
|
272
|
+
|
273
|
+
def delete_tables(self):
|
274
|
+
"""Deletes all tables that match the current table prefix."""
|
275
|
+
try:
|
276
|
+
query = """
|
277
|
+
SELECT table_name FROM information_schema.tables
|
278
|
+
WHERE table_schema = 'public' AND table_name LIKE %s;
|
279
|
+
"""
|
280
|
+
prefix_pattern = self.table_prefix + "%" # Dynamic prefix
|
281
|
+
logging.debug(f"Prefix pattern: {prefix_pattern}")
|
282
|
+
|
283
|
+
self.cur.execute(query, (prefix_pattern,))
|
284
|
+
tables = self.cur.fetchall()
|
285
|
+
|
286
|
+
if tables:
|
287
|
+
logging.info(f"Found {len(tables)} tables to delete.")
|
288
|
+
logging.debug(f"Tables to delete: {tables}")
|
289
|
+
|
290
|
+
for table in tables:
|
291
|
+
table_name = table[0]
|
292
|
+
logging.info(f"Dropping table: {table_name}")
|
293
|
+
|
294
|
+
drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
|
295
|
+
self.cur.execute(drop_query)
|
296
|
+
|
297
|
+
self.conn.commit()
|
298
|
+
logging.info("Successfully deleted matching tables.")
|
299
|
+
else:
|
300
|
+
logging.info("No tables found matching the prefix.")
|
301
|
+
|
302
|
+
except Exception as e:
|
303
|
+
logging.error(f"Error deleting tables: {e}", exc_info=True)
|
304
|
+
|
305
|
+
def status(self):
|
306
|
+
"""Logs the currently configured column settings."""
|
307
|
+
if self.column_list:
|
308
|
+
logging.info("Configured Columns:")
|
309
|
+
for column in self.column_list:
|
310
|
+
logging.info(f" - {column}")
|
311
|
+
else:
|
312
|
+
logging.info("No columns configured.")
|
313
|
+
|
314
|
+
logging.info(f"Dynamic Column: {self.column_dynamic if self.column_dynamic else 'None'}")
|
315
|
+
|
316
|
+
def format_table_name(self, input_column):
|
317
|
+
"""Formats an input column name to create a valid table name."""
|
318
|
+
cleaned = re.sub(r'[^a-zA-Z0-9_]', '', input_column)
|
319
|
+
return self.table_prefix + cleaned
|
320
|
+
|
321
|
+
def input(self, *args):
|
322
|
+
"""Handles data insertion by dynamically determining the table name and inserting values."""
|
323
|
+
column_dict = {}
|
324
|
+
self.table_name_dynamic = ''
|
325
|
+
|
326
|
+
for column_number, (column_name, _) in enumerate(self.column_list):
|
327
|
+
if column_name == self.column_dynamic:
|
328
|
+
self.table_name_dynamic = self.format_table_name(args[column_number])
|
329
|
+
column_dict[column_name] = args[column_number]
|
330
|
+
else:
|
331
|
+
column_dict[column_name] = args[column_number]
|
332
|
+
|
333
|
+
if self.table_name_dynamic:
|
334
|
+
self.create_table(self.table_name_dynamic, self.column_list)
|
335
|
+
|
336
|
+
self.insert_data(self.table_name_dynamic, column_dict)
|
@@ -1,15 +1,17 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dynamic-tables
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: A dynamic table creation and management library for PostgreSQL
|
5
|
-
Home-page: https://github.com/scottrodeo/
|
5
|
+
Home-page: https://github.com/scottrodeo/dynamic-tables-python
|
6
6
|
Author: Scott Rodeo
|
7
7
|
Author-email: signcactus@gmail.com
|
8
8
|
License: UNKNOWN
|
9
|
-
Project-URL: Author Website, https://patreon.com/scottrodeo
|
10
9
|
Description: # Dynamic Tables (Python)
|
10
|
+
|
11
11
|
A Python library for dynamically creating and managing PostgreSQL tables based on input data.
|
12
12
|
|
13
|
+
---
|
14
|
+
|
13
15
|
## 🚀 Features
|
14
16
|
- Automatically creates tables based on incoming data.
|
15
17
|
- Supports dynamic naming conventions.
|
@@ -19,16 +21,19 @@ Description: # Dynamic Tables (Python)
|
|
19
21
|
---
|
20
22
|
|
21
23
|
## 📥 Installation
|
22
|
-
|
24
|
+
|
25
|
+
### 1️⃣ Install via GitHub (Recommended for Development)
|
23
26
|
Clone the repository and install in editable mode:
|
27
|
+
|
24
28
|
```bash
|
25
29
|
git clone https://github.com/scottrodeo/dynamic-tables-python.git
|
26
30
|
cd dynamic-tables-python
|
27
31
|
pip install -e .
|
28
32
|
```
|
29
33
|
|
30
|
-
###
|
31
|
-
The package is available on PyPI,
|
34
|
+
### 2️⃣ Install Directly via `pip`
|
35
|
+
The package is available on PyPI, install it with:
|
36
|
+
|
32
37
|
```bash
|
33
38
|
pip install dynamic-tables
|
34
39
|
```
|
@@ -36,22 +41,21 @@ Description: # Dynamic Tables (Python)
|
|
36
41
|
---
|
37
42
|
|
38
43
|
## 🏃♂️ Running the Example
|
39
|
-
|
40
|
-
|
44
|
+
|
45
|
+
### 1️⃣ Quick Run (Without Installation)
|
46
|
+
Run the example script directly:
|
47
|
+
|
41
48
|
```bash
|
42
49
|
python3 examples/example.py
|
43
50
|
```
|
51
|
+
|
44
52
|
💡 *This works because the script dynamically adjusts `sys.path`.*
|
45
53
|
|
46
|
-
### **2️⃣ Recommended (After Installation)**
|
47
|
-
If you've installed the package (`pip install -e .`), simply run:
|
48
|
-
```bash
|
49
|
-
python3 examples/example.py
|
50
|
-
```
|
51
54
|
|
52
55
|
---
|
53
56
|
|
54
57
|
## 📌 Example Usage
|
58
|
+
|
55
59
|
Once installed, you can use `dynamic_tables` in your Python scripts:
|
56
60
|
|
57
61
|
```python
|
@@ -60,11 +64,12 @@ Description: # Dynamic Tables (Python)
|
|
60
64
|
# Initialize the dynamic table manager
|
61
65
|
tables = DynamicTables()
|
62
66
|
|
63
|
-
#
|
67
|
+
# Configure dynamic table properties
|
64
68
|
tables.set_table_prefix("dtbl_")
|
65
69
|
tables.set_columns("domain TEXT, category TEXT, lang TEXT")
|
66
70
|
tables.set_dynamic_column("domain")
|
67
71
|
|
72
|
+
# Insert dynamic data
|
68
73
|
tables.input("wikipedia.org", "cats", "en")
|
69
74
|
tables.input("wikipedia.org", "dogs", "en")
|
70
75
|
|
@@ -75,6 +80,7 @@ Description: # Dynamic Tables (Python)
|
|
75
80
|
---
|
76
81
|
|
77
82
|
## 🛠️ Available Functions
|
83
|
+
|
78
84
|
| Function | Description |
|
79
85
|
|----------|-------------|
|
80
86
|
| `set_columns("name TYPE, age TYPE")` | Define table schema |
|
@@ -83,20 +89,39 @@ Description: # Dynamic Tables (Python)
|
|
83
89
|
| `input(value1, value2, ...)` | Insert a new row dynamically |
|
84
90
|
| `show_tables()` | List all dynamically created tables |
|
85
91
|
| `show_columns("table_name")` | Show column details for a specific table |
|
92
|
+
| `show_columns_all()` | Show column details for all tables |
|
86
93
|
| `select_table("table_name")` | Retrieve all rows from a table |
|
87
94
|
| `delete_tables()` | Drop all tables matching the prefix |
|
95
|
+
| `create_table("table_name", [("column1", "TYPE"), ("column2", "TYPE")])` | Create a table dynamically |
|
96
|
+
| `insert_data("table_name", {"column1": value1, "column2": value2})` | Insert data into a specific table |
|
97
|
+
| `get_tables()` | Retrieve a list of all tables in the database |
|
98
|
+
| `get_columns("table_name")` | Retrieve all columns for a given table |
|
99
|
+
| `get_table_rows("table_name")` | Retrieve all rows from a table |
|
100
|
+
| `connectHC("dbname", "user", "password", "host")` | Connect using hardcoded credentials |
|
101
|
+
| `connectJSON("config.json")` | Connect using credentials from a JSON config file |
|
102
|
+
| `connectENVS()` | Connect using environment variables |
|
103
|
+
| `connection_open("dbname", "user", "password", "host")` | Open a PostgreSQL database connection |
|
104
|
+
| `connection_close()` | Close the database connection |
|
105
|
+
| `status()` | Show the current configuration status |
|
106
|
+
| `show_db()` | Display the connected database name |
|
107
|
+
| `setup_logging(level, log_to_file)` | Configure logging settings |
|
108
|
+
| `change_log_level("LEVEL")` | Change the logging level at runtime |
|
109
|
+
| `show_version()` | Display the current version of the library |
|
88
110
|
|
89
111
|
---
|
90
112
|
|
91
113
|
## ⚡ Development
|
92
|
-
|
93
|
-
|
114
|
+
|
115
|
+
### Running Tests
|
116
|
+
Run the test suite:
|
117
|
+
|
94
118
|
```bash
|
95
119
|
pytest tests/
|
96
120
|
```
|
97
121
|
|
98
|
-
###
|
122
|
+
### Linting
|
99
123
|
Ensure your code follows best practices:
|
124
|
+
|
100
125
|
```bash
|
101
126
|
flake8 dynamic_tables/
|
102
127
|
```
|
@@ -104,7 +129,8 @@ Description: # Dynamic Tables (Python)
|
|
104
129
|
---
|
105
130
|
|
106
131
|
## 🤝 Contributing
|
107
|
-
|
132
|
+
|
133
|
+
Contributions are welcome! To contribute:
|
108
134
|
1. Fork the repository.
|
109
135
|
2. Create a new branch (`git checkout -b feature-branch`).
|
110
136
|
3. Commit your changes (`git commit -m "Added new feature"`).
|
@@ -114,18 +140,19 @@ Description: # Dynamic Tables (Python)
|
|
114
140
|
---
|
115
141
|
|
116
142
|
## 📄 License
|
143
|
+
|
117
144
|
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
118
145
|
|
119
146
|
---
|
120
147
|
|
121
148
|
## 🌎 Links
|
149
|
+
|
122
150
|
- **GitHub Repository:** [Dynamic Tables (Python)](https://github.com/scottrodeo/dynamic-tables-python)
|
123
|
-
- **Documentation:** *(To be added)*
|
124
151
|
- **Issue Tracker:** [Report Issues](https://github.com/scottrodeo/dynamic-tables-python/issues)
|
125
152
|
|
126
153
|
---
|
127
154
|
|
128
|
-
###
|
155
|
+
### 🚀 Happy Coding!
|
129
156
|
|
130
157
|
|
131
158
|
Platform: UNKNOWN
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
2
2
|
|
3
3
|
setup(
|
4
4
|
name="dynamic_tables",
|
5
|
-
version="0.
|
5
|
+
version="0.2.0",
|
6
6
|
packages=find_packages(),
|
7
7
|
install_requires=[
|
8
8
|
"psycopg2",
|
@@ -12,10 +12,7 @@ setup(
|
|
12
12
|
description="A dynamic table creation and management library for PostgreSQL",
|
13
13
|
long_description=open("README.md").read(),
|
14
14
|
long_description_content_type="text/markdown",
|
15
|
-
url="https://github.com/scottrodeo/
|
16
|
-
project_urls={
|
17
|
-
"Author Website": "https://patreon.com/scottrodeo",
|
18
|
-
},
|
15
|
+
url="https://github.com/scottrodeo/dynamic-tables-python",
|
19
16
|
classifiers=[
|
20
17
|
"Programming Language :: Python :: 3",
|
21
18
|
"License :: OSI Approved :: MIT License",
|
@@ -1,224 +0,0 @@
|
|
1
|
-
# this is dynamic_tables.py
|
2
|
-
|
3
|
-
import psycopg2, re
|
4
|
-
from psycopg2 import sql
|
5
|
-
|
6
|
-
class DynamicTables:
|
7
|
-
|
8
|
-
def __init__(self):
|
9
|
-
"""Initialize the class by calling self.initialize() to set up default values."""
|
10
|
-
self.initialize()
|
11
|
-
|
12
|
-
def initialize(self):
|
13
|
-
"""Sets up default attributes for the table structure."""
|
14
|
-
self.column_list = []
|
15
|
-
self.column_dynamic = ''
|
16
|
-
self.table_prefix = 'dtbl_'
|
17
|
-
self.table_name_dynamic = ''
|
18
|
-
|
19
|
-
def connection_open(self, dbname, user, password, host):
|
20
|
-
"""Opens a connection to the PostgreSQL database and initializes the cursor."""
|
21
|
-
self.conn = psycopg2.connect(
|
22
|
-
dbname=dbname,
|
23
|
-
user=user,
|
24
|
-
password=password,
|
25
|
-
host=host
|
26
|
-
)
|
27
|
-
self.cur = self.conn.cursor()
|
28
|
-
|
29
|
-
def connectHC(self, dbname, user, password, host):
|
30
|
-
"""Helper function to open a connection using hardcoded credentials."""
|
31
|
-
self.connection_open(dbname, user, password, host)
|
32
|
-
|
33
|
-
def connectJSON(self):
|
34
|
-
"""Opens a database connection using credentials from a JSON config file."""
|
35
|
-
import json
|
36
|
-
with open("config.json") as config_file:
|
37
|
-
config = json.load(config_file)
|
38
|
-
self.conn = psycopg2.connect(**config)
|
39
|
-
self.cur = self.conn.cursor()
|
40
|
-
|
41
|
-
def connectENVS(self):
|
42
|
-
"""Opens a database connection using environment variables."""
|
43
|
-
import os
|
44
|
-
self.conn = psycopg2.connect(
|
45
|
-
host=os.getenv("DTABLES_ENVS_PGSQL_HOST"),
|
46
|
-
user=os.getenv("DTABLES_ENVS_PGSQL_USER"),
|
47
|
-
password=os.getenv("DTABLES_ENVS_PGSQL_PASSWORD"),
|
48
|
-
database=os.getenv("DTABLES_ENVS_PGSQL_DATABASE")
|
49
|
-
)
|
50
|
-
self.cur = self.conn.cursor()
|
51
|
-
|
52
|
-
def connection_close(self):
|
53
|
-
"""Closes the database cursor and connection."""
|
54
|
-
self.cur.close()
|
55
|
-
self.conn.close()
|
56
|
-
|
57
|
-
def close(self):
|
58
|
-
"""Alias for connection_close() to improve readability."""
|
59
|
-
self.connection_close()
|
60
|
-
|
61
|
-
def format_table_name(self, input_column):
|
62
|
-
"""Formats an input column name to create a valid table name."""
|
63
|
-
cleaned = re.sub(r'[^a-zA-Z0-9_]', '', input_column)
|
64
|
-
return self.table_prefix + cleaned
|
65
|
-
|
66
|
-
def input(self, *args):
|
67
|
-
"""Handles data insertion by dynamically determining the table name and inserting values."""
|
68
|
-
column_dict = {}
|
69
|
-
self.table_name_dynamic = ''
|
70
|
-
|
71
|
-
for column_number, (column_name, _) in enumerate(self.column_list):
|
72
|
-
if column_name == self.column_dynamic:
|
73
|
-
self.table_name_dynamic = self.format_table_name(args[column_number])
|
74
|
-
column_dict[column_name] = args[column_number]
|
75
|
-
else:
|
76
|
-
column_dict[column_name] = args[column_number]
|
77
|
-
|
78
|
-
if self.table_name_dynamic:
|
79
|
-
self.create_table(self.table_name_dynamic, self.column_list)
|
80
|
-
|
81
|
-
self.insert_data(self.table_name_dynamic, column_dict)
|
82
|
-
|
83
|
-
def insert_data(self, table_name, data_dict):
|
84
|
-
"""Inserts data into a dynamically created table."""
|
85
|
-
columns = data_dict.keys()
|
86
|
-
values = list(data_dict.values())
|
87
|
-
|
88
|
-
query = sql.SQL("""
|
89
|
-
INSERT INTO {} ({})
|
90
|
-
VALUES ({});
|
91
|
-
""").format(
|
92
|
-
sql.Identifier(table_name),
|
93
|
-
sql.SQL(', ').join(map(sql.Identifier, columns)),
|
94
|
-
sql.SQL(', ').join(sql.Placeholder() for _ in columns)
|
95
|
-
)
|
96
|
-
|
97
|
-
self.cur.execute(query, values)
|
98
|
-
self.conn.commit()
|
99
|
-
|
100
|
-
def create_table(self, table_name, columns):
|
101
|
-
"""Creates a table dynamically if it does not already exist."""
|
102
|
-
column_definitions = sql.SQL(", ").join(
|
103
|
-
sql.SQL("{} {}").format(sql.Identifier(col_name), sql.SQL(col_type))
|
104
|
-
for col_name, col_type in columns
|
105
|
-
)
|
106
|
-
|
107
|
-
query = sql.SQL("""
|
108
|
-
CREATE TABLE IF NOT EXISTS {} (
|
109
|
-
id SERIAL PRIMARY KEY,
|
110
|
-
{}
|
111
|
-
);
|
112
|
-
""").format(sql.Identifier(table_name), column_definitions)
|
113
|
-
|
114
|
-
self.cur.execute(query)
|
115
|
-
self.conn.commit()
|
116
|
-
|
117
|
-
def show_db(self):
|
118
|
-
"""Lists all available databases."""
|
119
|
-
self.cur.execute("SELECT datname FROM pg_database WHERE datistemplate = false;")
|
120
|
-
for row in self.cur.fetchall():
|
121
|
-
print(row)
|
122
|
-
|
123
|
-
def show_tables(self):
|
124
|
-
"""Fetch and return a list of all table names."""
|
125
|
-
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
126
|
-
tables = self.cur.fetchall()
|
127
|
-
|
128
|
-
if tables:
|
129
|
-
table_list = [table[0] for table in tables] # Convert to a simple list of table names
|
130
|
-
print("\n".join(table_list)) # Print for debugging
|
131
|
-
return table_list
|
132
|
-
else:
|
133
|
-
print("No tables found.")
|
134
|
-
return [] # Return an empty list instead of None
|
135
|
-
|
136
|
-
def show_columns(self, table_name):
|
137
|
-
"""Displays all columns and their data types for a given table."""
|
138
|
-
try:
|
139
|
-
query = sql.SQL("""
|
140
|
-
SELECT column_name, data_type
|
141
|
-
FROM information_schema.columns
|
142
|
-
WHERE table_name = %s
|
143
|
-
ORDER BY ordinal_position;
|
144
|
-
""")
|
145
|
-
self.cur.execute(query, (table_name,))
|
146
|
-
columns = self.cur.fetchall()
|
147
|
-
|
148
|
-
if columns:
|
149
|
-
print(f"Columns in table '{table_name}':")
|
150
|
-
for column_name, data_type in columns:
|
151
|
-
print(f" - {column_name}: {data_type}")
|
152
|
-
else:
|
153
|
-
print(f"No columns found for table '{table_name}' or the table does not exist.")
|
154
|
-
except Exception as e:
|
155
|
-
print(f"Error retrieving columns for '{table_name}': {e}")
|
156
|
-
|
157
|
-
def show_columns_all(self):
|
158
|
-
"""Lists column details for all tables."""
|
159
|
-
self.cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';")
|
160
|
-
for table in self.cur.fetchall():
|
161
|
-
self.show_columns(table[0])
|
162
|
-
|
163
|
-
def select_table(self, table_name):
|
164
|
-
"""Retrieves and prints all rows from the specified table."""
|
165
|
-
query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name))
|
166
|
-
self.cur.execute(query)
|
167
|
-
rows = self.cur.fetchall()
|
168
|
-
|
169
|
-
if rows:
|
170
|
-
for row in rows:
|
171
|
-
print(f"Row: {row}")
|
172
|
-
else:
|
173
|
-
print(f"Table '{table_name}' exists but has no data.")
|
174
|
-
|
175
|
-
return rows
|
176
|
-
|
177
|
-
def delete_tables(self):
|
178
|
-
"""Deletes all tables that match the current table prefix."""
|
179
|
-
query = """
|
180
|
-
SELECT table_name FROM information_schema.tables
|
181
|
-
WHERE table_schema = 'public' AND table_name LIKE %s;
|
182
|
-
"""
|
183
|
-
prefix_pattern = self.table_prefix + "%" # Dynamic prefix
|
184
|
-
print("prefix_pattern:" + prefix_pattern) # Debugging output
|
185
|
-
self.cur.execute(query, (prefix_pattern,))
|
186
|
-
|
187
|
-
tables = self.cur.fetchall()
|
188
|
-
print("DEBUG - Found tables to delete:", tables) # Debugging output
|
189
|
-
|
190
|
-
for table in tables:
|
191
|
-
table_name = table[0]
|
192
|
-
print(f"Dropping table: {table_name}")
|
193
|
-
|
194
|
-
drop_query = sql.SQL("DROP TABLE IF EXISTS {} CASCADE;").format(sql.Identifier(table_name))
|
195
|
-
self.cur.execute(drop_query)
|
196
|
-
|
197
|
-
self.conn.commit()
|
198
|
-
|
199
|
-
def set_columns(self, input_columns):
|
200
|
-
"""Sets the columns for table creation based on user input."""
|
201
|
-
self.column_list = []
|
202
|
-
for column in input_columns.split(','):
|
203
|
-
column = column.strip()
|
204
|
-
parts = column.split(maxsplit=1)
|
205
|
-
if len(parts) == 2:
|
206
|
-
self.column_list.append((parts[0], parts[1]))
|
207
|
-
else:
|
208
|
-
print(f"Invalid column format: '{column}'")
|
209
|
-
|
210
|
-
def set_table_prefix(self, input_prefix):
|
211
|
-
"""Defines a custom table name prefix."""
|
212
|
-
self.table_prefix = input_prefix
|
213
|
-
|
214
|
-
def set_dynamic_column(self, input_column):
|
215
|
-
"""Sets the column that determines dynamic table names."""
|
216
|
-
self.column_dynamic = input_column
|
217
|
-
|
218
|
-
def status(self):
|
219
|
-
"""Displays the currently configured column settings."""
|
220
|
-
print('\nConfigured Columns:')
|
221
|
-
for column in self.column_list:
|
222
|
-
print(column)
|
223
|
-
print('\nDynamic Column:\n', self.column_dynamic, '\n')
|
224
|
-
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|